USERV Insurance was developed in 2006 as a standard business rules use case that all the vendors could implement so that prospects would have a common example to use when evaluating business rules engines. Back in 2006 this was a prominent feature of the Business Rules Forum. Each vendor would present their solution to the entire conference. The original Corticon solution was implemented using version 4.3. This document presents the solution in the latest version of Corticon (5.4)
The original USERV Use Case Specification is available on the DM Community website.
You may follow this link to get a very detailed description of the business rules, a related fact model, business processes, and test cases
Below is a walk though of the rule sheets comprising the Corticon solution.
Note that this is not intended to be a tutorial on Corticon but rather an explanation of how the USERV use case was modeled with Corticon. Some details will be provided where necessary to understand how Corticon processes rules but it is assumed that readers are already familiar with the concept of business rules engines and in particular the use of decision tables as the primary means to represent business logic.
More details regarding Corticon features, functionality and concepts can be found in the online documentation available at http://documentation.progress.com/output/ua/Corticon
Every piece of software, whether it’s a traditional programming language or a rule engine, needs to define the data it will work with. In the Corticon world this is referred to as a Vocabulary.
The vocabulary in Corticon contains details about the business objects and their relationships, their attributes, data types and possible values (it can also contain the mapping of business objects to tables and attributes to columns in a database).
The vocabulary was constructed to match the data model in the original USERV specification. It can be automatically imported from a variety of sources.
Custom data types can be defined for attributes that must be restricted to specific values.
These values can be typed in or loaded from a database.
Observe that the icons for the business objects have little disk decorations on them. This is because one of the features of Corticon is the ability to read data directly from a database. This is done automatically and transparently to the rule author. No SQL needs to be written for this.
The diagram below shows the relationships or associations between the objects. Most of the attributes have been hidden in order to keep the diagram small. The asterisk marks the primary key for the database.
And in SQL
Querying the Vehicle table might show something like this:
The business Party table (which will contain the drivers) might look like this:
The last two columns show how these records are associated with other business objects.
Fortunately as a rule author you do not need to be concerned with this technical detail. Corticon will handle that automatically so that if your rules need the vehicles associated with a given policy for a given client, Corticon will automatically create the correct SQL to do the retrieval.
Corticon automatically determines the correct SQL JOIN expression from the database schema for related tables.
Corticon can also update the database with the new results after the rules have executed.
Corticon supports a wide variety of relational databases directly:
And, in addition, non-relational or proprietary data sources can be accessed using the Progress Data Direct Cloud connectors.
These enable simple, fast connections to cloud and on-premise data regardless of the source—SaaS apps, big data stores, relational databases, and more—using a single ODBC, JDBC driver, or OData-based API.
Note: This feature is available even if you do not use Corticon – it will work with any vendor’s rule engine.
More information on these data sources is available here: https://www.progress.com/products/datadirect-cloud
The entire decision comprises four main parts:
The structure of a Corticon decision service is represented by a Rule Flow Diagram.
In order to keep the diagram uncluttered, the actual rule sheets that are inside each of the inner sub flows have been omitted. In the subsequent discussion we will show those details.
A Corticon rule sheet consists of several parts:
We’ll look at each of the rule sheets in turn and with each one there will be some relevant discussion of the rule modeling techniques (indicated in parentheses) that might apply. We’ll show how Corticon can find the significant number of ambiguities that are in the original specification. Some of the later rule sheets are very similar and so will be presented without discussion in the appendix.
There are two rule sheets in this sub flow.
The Scope section shows that a Client may have one or more Service (referred to using the alias services. In the condition, ->uniqueCount is an operator that determines the number of unique values of the attribute productType across all the services belonging to any given Client. Corticon has a rich set of operators for performing operations on collections (these are similar to the aggregation and other features in the DMN). The built in operators can be supplemented with ones of your own design by writing them in Java.
The alias “services” refers to ALL the services associated with a particular client (a one-to-many association). The ->sum operator (a built in aggregation operator) adds up all the appropriate servicePremiums (and balances) for each of the services.
The scope section is how Corticon “knows” that clients have many services and that they should all be considered when evaluating the rule.
If the vehicle considered for insurance matches the year (including wildcard 0000), make, and model (including wildcard "any") of the High Theft Probability Auto List, then the vehicle is a High Theft Probability risk
Note: The dash ‘-‘ indicates that a particular condition is not applicable in that rule
The alias highTheftList is a lookup table read from a database
Example of the table:
Corticon can load the table when it’s required and then the rules will locate any record that meets any of the four cases.
As an alternative to storing the high theft vehicles in a database table we could simply have made them into entries in a rule sheet. This may be faster than doing a database lookup.
Here are the rules for determining the Potential Theft Category exactly as specified in the original documentation. But are they correct?
Here are the same rules modeled in Corticon:
The Corticon Conflict Checker tells us that there are conflicts (the pink columns):
How should we rate a convertible that costs $30,000 that is not on the high theft list?
Rule 1 says “High” but rule 4 says “Moderate”.
Corticon also detects a second conflict:
Let’s assume in both these cases “convertible” wins and we want the rating to be “High”.
In general there are two ways to resolve conflicts:
The preferred method is #1. In this case rules 4 and 5 can be modified to explicitly exclude Convertibles:
Rules 2 and 3 also overlap rule 1, they do not conflict because they conclude the same “High” rating. Corticon will execute both rules.
An alternative method is to explicitly provide an override:
Effectively an override is really just another business rule. So if it’s important to understand what the override is really saying it’s usually better to represent it as an actual rule entry (case #1). If there are a lot of overrides it can be hard to understand what’s going on.
Notice the use of the filters to ensure that the rules only get applied to Vehicle Insurance policies and vehicles that are cars. Boats are presumably handled differently. The alias car is used to make it very clear that the rule applies to cars.
These rules also contain ambiguities:
By making rule 5 override rules 2, 3 and 4 we can resolve this ambiguity.
Here are the original rules for auto eligibility. Do you see any problems with these rules?
Since it’s hard to see the flaws in the English statements, let’s first model this in Corticon exactly as stated:
First the ambiguity checker will tell us that rule 1 is in conflict with rules 3 and 4 and 5
Secondly Corticon will tell us there is a logical loop since rule 5 references a value that is set in its own action. While Corticon can handle a self-referencing rule it’s not the clearest way of expressing the rule.
A better way might be to enumerate the specific rules that assign “Eligible”.
A quick way to set this up is to use the completeness checker to automatically add the missing conditions (5, 6, and 7). Corticon can’t decide what action is required – it’s not that smart! – you have to add that)
Note: In this rule sheet we have chosen to resolve the conflicts by using overrides. Sometimes it might actually be simpler than trying to adjust the rules to avoid ambiguity.
And even this is not the final solution. If we run the completeness checker, Corticon will want to know what action it should take for these conditions:
You might argue that these conditions should not arise. But as a general best practice it’s safer to accommodate all possible outcomes. Sooner or later they will occur either as the result of bad data passed in from a client application or a rule modification that misspelled a word.
Adding these error catching rules can make the rule sheet a bit bigger so an alternative is to have separate rule sheets that do the data validation. This technique can be useful because rule sheets can be reused in different decisions so you only need to develop the data validation logic once rather than repeating it in each rule sheet where an attribute is tested.
Another way to handle the “Eligible” case is to say a vehicle is considered eligible by default unless excluded by one of the four rules.
This can be done conveniently by putting the action in column zero (which does not require any conditions). And then you don’t need rules 5, 6 and 7.
Note: Setting “Eligible” explicitly is a better practice if you need to know the precise reason for assigning “Eligible”. If you don’t care about the reason then the default method is acceptable.
This pattern is most often seen with validation – you care about the specific reason when the data is invalid. But if it’s valid you usually don’t need to know the all the reasons why.
This rule sheet also has an accompanying SCOPE and FILTER section that defines the local meaning of terms such as “car” (which is just one type of Vehicle), “driver” (a ServiceParticipant), “policy” (a type of Service) and “policyOwner” (a type of BusinessParty).
We could have used those original terms but defining aliases enables us to make rules that are easier to read.
The filters ensure that we only select the “BusinessParty” that is identified as the policyOwner. Similarly the alias “car” is a Vehicle filtered to only those of type=’car’
In effect defining a filter is like adding that condition across every rule in the rule sheet.
If necessary you can use complex expressions in the filters (such as ->sum, ->max, ->min, ->avg, ->exists, ->forAll, ->substring, ->contains, ->yearsBetween, ->equalsIgnoreCase etc.)
You can also use the filter section to “join” two entities that do not have an explicit association defined (just like you might do in SQL with database tables). Then the rules will process them as a matched set.
The remainder of the rule sheets are described in the Appendix.
When all the individual rule sheets are connected up using the rule flow diagram we have a Decision Service that can be published and executed.
Let’s look at the scenarios (in the interest of space just V1 and V2 are presented.)
Note also that the results presented here are based on the 2006 dates specified in the scenario – not the current date.
If you use 2015 then your results may be different. (The drivers and vehicles will be older).
Corticon supports effective dating so it can be run for any date, past or future.
Sara 4/2/2006 Preferred (has at least 3 products) $2758.50
Sara on 7/8/2006 Still Preferred (Grandfathered in): $2758.50
Mark on 7/8/2006 Not Preferred under the new rules so pays more: $3008.50
Mark on 7/8/2006 Angie moves to CA and has 3 accidents: $4878.50
This complete audit trail was generated from the rule statements
In fact both forms can be maintained in the rule statement section of the rule sheet. E.g:
Original rule statements (IF... THEN format)
Customized version (FACT…CONCLUSION format)
Before moving to CA this is how the rule model rates Angie.
When she moves to CA and has three accidents Angie gets rated like this:
This affects both the eligibility score and the premium.
And the policy gets these messages:
Incidentally if we run Sara in 2014 the cars will be older (but keep Spenser at 17) we get
Adjusting ages (Spenser is really 27 and no longer Young) gives
This rule sheet also introduces the idea of a “Typical” driver, one that is neither Young nor Senior.
4 and 5 can be merged automatically using the Corticon rule compression feature
Null is used in case the input data for training certification is missing.
Clients can have one or more policy (an alias for Service). A policy can have one or more participant and one or more car. Unlike programming languages which would require the programmer to create various loops to iterate over the repeating objects, Corticon is smart enough to know how to interpret the actions of the rules. It knows to apply the actions to ALL policies for this client. And for every policy it applies the actions to ALL the participants and vehicles. Furthermore, Corticon knows (from the filter expression) that we are only interested in the policies that are for Vehicle Insurance and only vehicles that are cars. So those three very simple actions could end up doing a lot of work if there are many policies with many drivers and vehicles. This might be the case if the Client was a taxi company.
The keyword cellValue allows a value from the rule column to be used in the action.
This sheet combines a number of unrelated attributes. E.g. vehicle eligibility score is independent of driver eligibility score and client score (any or all may get added). Should these be split on to separate sheets? i.e. rules 1,2,3 are mutually exclusive and 4,5,6 are also mutually exclusive. Should the eligibility scores be kept separate (for vehicle, and driver and client) and totaled at the end? If we did this we’d have visibility of the contribution of each factor and this could be displayed in the bill (or audit report).
The action is in column zero since there are no conditions
Using this Scope:
Column zero is a non-conditional rule and gets executed first to calculate the sum of the vehicle premiums and driver premiums. Then rules 1 and 2 make deductions from that total premium.
The alias “car” refers to ALL of the vehicles on a specific policy belonging to a particular client
This rule sheet simply displays the final outcome of the decision:
The only actions are to post the final messages
Download PDF version.