Chapter 3. Inference and truth maintenance in the decision engine
The basic function of the decision engine is to match data to business rules and determine whether and how to execute rules. To ensure that relevant data is applied to the appropriate rules, the decision engine makes inferences based on existing knowledge and performs the actions based on the inferred information.
For example, the following DRL rule determines the age requirements for adults, such as in a bus pass policy:
Rule to define age requirement
rule "Infer Adult" when $p : Person(age >= 18) then insert(new IsAdult($p)) end
Based on this rule, the decision engine infers whether a person is an adult or a child and performs the specified action (the then
consequence). Every person who is 18 years old or older has an instance of IsAdult
inserted for them in the working memory. This inferred relation of age and bus pass can then be invoked in any rule, such as in the following rule segment:
$p : Person() IsAdult(person == $p)
In many cases, new data in a rule system is the result of other rule executions, and this new data can affect the execution of other rules. If the decision engine asserts data as a result of executing a rule, the decision engine uses truth maintenance to justify the assertion and enforce truthfulness when applying inferred information to other rules. Truth maintenance also helps to identify inconsistencies and to handle contradictions. For example, if two rules are executed and result in a contradictory action, the decision engine chooses the action based on assumptions from previously calculated conclusions.
The decision engine inserts facts using either stated or logical insertions:
-
Stated insertions: Defined with
insert()
. After stated insertions, facts are generally retracted explicitly. (The term insertion, when used generically, refers to stated insertion.) -
Logical insertions: Defined with
insertLogical()
. After logical insertions, the facts that were inserted are automatically retracted when the conditions in the rules that inserted the facts are no longer true. The facts are retracted when no condition supports the logical insertion. A fact that is logically inserted is considered to be justified by the decision engine.
For example, the following sample DRL rules use stated fact insertion to determine the age requirements for issuing a child bus pass or an adult bus pass:
Rules to issue bus pass, stated insertion
rule "Issue Child Bus Pass" when $p : Person(age < 18) then insert(new ChildBusPass($p)); end rule "Issue Adult Bus Pass" when $p : Person(age >= 18) then insert(new AdultBusPass($p)); end
These rules are not easily maintained in the decision engine as bus riders increase in age and move from child to adult bus pass. As an alternative, these rules can be separated into rules for bus rider age and rules for bus pass type using logical fact insertion. The logical insertion of the fact makes the fact dependent on the truth of the when
clause.
The following DRL rules use logical insertion to determine the age requirements for children and adults:
Children and adult age requirements, logical insertion
rule "Infer Child" when $p : Person(age < 18) then insertLogical(new IsChild($p)) end rule "Infer Adult" when $p : Person(age >= 18) then insertLogical(new IsAdult($p)) end
For logical insertions, your fact objects must override the equals
and hashCode
methods from the java.lang.Object
object according to the Java standard. Two objects are equal if their equals
methods return true
for each other and if their hashCode
methods return the same values. For more information, see the Java API documentation for your Java version.
When the condition in the rule is false, the fact is automatically retracted. This behavior is helpful in this example because the two rules are mutually exclusive. In this example, if the person is younger than 18 years old, the rule logically inserts an IsChild
fact. After the person is 18 years old or older, the IsChild
fact is automatically retracted and the IsAdult
fact is inserted.
The following DRL rules then determine whether to issue a child bus pass or an adult bus pass and logically insert the ChildBusPass
and AdultBusPass
facts. This rule configuration is possible because the truth maintenance system in the decision engine supports chaining of logical insertions for a cascading set of retracts.
Rules to issue bus pass, logical insertion
rule "Issue Child Bus Pass" when $p : Person() IsChild(person == $p) then insertLogical(new ChildBusPass($p)); end rule "Issue Adult Bus Pass" when $p : Person() IsAdult(person =$p) then insertLogical(new AdultBusPass($p)); end
When a person turns 18 years old, the IsChild
fact and the person’s ChildBusPass
fact is retracted. To these set of conditions, you can relate another rule that states that a person must return the child pass after turning 18 years old. When the decision engine automatically retracts the ChildBusPass
object, the following rule is executed to send a request to the person:
Rule to notify bus pass holder of new pass
rule "Return ChildBusPass Request" when $p : Person() not(ChildBusPass(person == $p)) then requestChildBusPass($p); end
The following flowcharts illustrate the life cycle of stated and logical insertions:
Figure 3.1. Stated insertion
Figure 3.2. Logical insertion
When the decision engine logically inserts an object during a rule execution, the decision engine justifies the object by executing the rule. For each logical insertion, only one equal object can exist, and each subsequent equal logical insertion increases the justification counter for that logical insertion. A justification is removed when the conditions of the rule become untrue. When no more justifications exist, the logical object is automatically retracted.
3.1. Fact equality modes in the decision engine
The decision engine supports the following fact equality modes that determine how the decision engine stores and compares inserted facts:
-
identity
: (Default) The decision engine uses anIdentityHashMap
to store all inserted facts. For every new fact insertion, the decision engine returns a newFactHandle
object. If a fact is inserted again, the decision engine returns the originalFactHandle
object, ignoring repeated insertions for the same fact. In this mode, two facts are the same for the decision engine only if they are the very same object with the same identity. -
equality
: The decision engine uses aHashMap
to store all inserted facts. The decision engine returns a newFactHandle
object only if the inserted fact is not equal to an existing fact, according to theequals()
method of the inserted fact. In this mode, two facts are the same for the decision engine if they are composed the same way, regardless of identity. Use this mode when you want objects to be assessed based on feature equality instead of explicit identity.
As an illustration of fact equality modes, consider the following example facts:
Example facts
Person p1 = new Person("John", 45); Person p2 = new Person("John", 45);
In identity
mode, facts p1
and p2
are different instances of a Person
class and are treated as separate objects because they have separate identities. In equality
mode, facts p1
and p2
are treated as the same object because they are composed the same way. This difference in behavior affects how you can interact with fact handles.
For example, assume that you insert facts p1
and p2
into the decision engine and later you want to retrieve the fact handle for p1
. In identity
mode, you must specify p1
to return the fact handle for that exact object, whereas in equality
mode, you can specify p1
, p2
, or new Person("John", 45)
to return the fact handle.
Example code to insert a fact and return the fact handle in identity
mode
ksession.insert(p1); ksession.getFactHandle(p1);
Example code to insert a fact and return the fact handle in equality
mode
ksession.insert(p1); ksession.getFactHandle(p1); // Alternate option: ksession.getFactHandle(new Person("John", 45));
To set the fact equality mode, use one of the following options:
-
Set the system property
drools.equalityBehavior
toidentity
(default) orequality
. Set the equality mode while creating the KIE base programmatically:
KieServices ks = KieServices.get(); KieBaseConfiguration kieBaseConf = ks.newKieBaseConfiguration(); kieBaseConf.setOption(EqualityBehaviorOption.EQUALITY); KieBase kieBase = kieContainer.newKieBase(kieBaseConf);
Set the equality mode in the KIE module descriptor file (
kmodule.xml
) for a specific Red Hat Decision Manager project:<kmodule> ... <kbase name="KBase2" default="false" equalsBehavior="equality" packages="org.domain.pkg2, org.domain.pkg3" includes="KBase1"> ... </kbase> ... </kmodule>