Adjusting conditions

Most of the execution time is taken up by the pattern-matching process. Consequently, the most efficient way of improving performance in rulesets consists in modifying the condition part of rules.

Fast path: You optimize the performance of the Fastpath execution mode by modifying the condition part of rules. To improve the performance of the Fastpath execution algorithm, you can change the order of tests, or the order of conditions that are shared between several rules.

Execution order of tests and definitions

If a test depends on one definition, the test is evaluated as soon as the definition exists. In the case where several definitions are created in the definition part of the rule, it means that a test might be evaluated before all the definitions are created.

In the following example, the test the age of 'the winning customer' is at least 18 depends on the definition the winning customer and does not depend on 'the email'. Therefore, this first test is evaluated before the definition 'the email' is created.
definitions
   set 'the winning customer' to a Customer ;
   set 'the email' to  the email of 'the winning the customer'  ;
if
   the age of 'the winning customer' is at least 18
   and 'the email' is defined 
then
   print "Send coupon to customer via email.";

Ordering tests

The order in which tests are carried out in rule conditions affects the performance of the pattern-matching process. To get the best performance for a specific condition, place the most discriminant tests at the start. This position accelerates the selection of objects in the discrimination tree for tests that involve constants. Also, when you place the most discriminant tests at the start, you know sooner when an object does not satisfy the tests between conditions in the joins.

BAL building blocks

The decision engine runs on Jakarta EE and integrates Enterprise JavaBeans components. You can optimize performance by using BAL building blocks, and execution modes appropriately.

Rules can be internally rewritten by the engine to enable automatic optimization of the rules. By using the from and in building blocks, you reduce the number of objects on which pattern matching is applied, and hence the number of evaluations carried out. The rule engine automatically rewrites rules to use these building blocks whenever possible.

Sharing conditions

If the first N conditions of two rules are identical, these rules share the same portion of the network. As a consequence, searches for objects that satisfy these first N conditions are done only once for all the rules that share these conditions. It is therefore a good idea to modify the order of rule conditions so that they share the network as much as possible.

Note:

You cannot share conditions in the sequential execution mode.

Ordering conditions in rules

Place the most selective conditions, or groups of conditions, at the beginning of tests. In this way, the objects that prevent a rule from being run are removed sooner in the process. Tokens spend less time in the RetePlus network, joins require less memory, and fewer tests are necessary.

Example of the effect of condition order on RetePlus performance

Here is a rule with three object classes.

rule filter {
   when {
      A (a1==3; ?x:a2);
      B (b1==2; ?y:b2; b3==?x);
      C (c1==?y);
   }
   then {
      System.out.println("filter");
   }
}

Let’s work on this example.

  1. Imagine different contents for the working memory:

    • There are five objects of class A and their a2 attribute is 10.

    • There is an object of class B whose b2 attribute is 7 and b3 attribute is 10.

    • There is an object of class B whose b2 attribute is 4 and b3 attribute is 10.

    • There are 28 objects of class B. Their b3 attribute is 10 and their b2 attribute is neither 4 nor 7. In other words, there are thirty class B objects in all.

    • There is one object of class C® and its c1 attribute is 4.

  2. If you were to draw the corresponding RetePlus network, the contents of the first join node would be quite different.

  3. It now contains 155 pairs of objects, which can be described like this:

    • Five pairs are formed by the objects of class A and the object of class B whose b2 is 7 and b3 is 10.

    • 150 pairs (that is, (5 * (28 + 1 + 1))) are formed by the objects of class A and the objects of class B whose b3 attribute is 10.

  4. If you now add an object of class C whose c1 attribute is 7, the work of the second join node consists of doing 155 tests, between the B object of each of the 155 pairs of the first join and the C object that you have just added, to verify that attributes b2 and c1 have the same value.

  5. Now, suppose you create a filter2 rule by changing the order of the conditions of the filter rule so that it is shown as follows:

    rule filter2 {
       when {
          C (?y:c1);
          B (b1==2; b2==?y; ?x:b3);
          A (a1==3; a2==?x);
              }
       then {
          System.out.println("filter2");
       }
    }
    

    For the same initial working memory as before, the first join node, corresponding to the first two conditions, now contains 30 (instead of 155) pairs, formed by the class C object and the 30 class B objects whose b2 attribute is 4 and b3 attribute is 10.

  6. If you now add an object of the C class whose c1 attribute is 7, the work of the first join node consists of doing 30 tests between the newly added object and the 30 class B objects in memory. This causes us to add a new pair, formed by the C object that you have just added and the B object whose b2 attribute is 7.

  7. After all this is done, the second join node is activated. It does 30 tests, between the B object of each pair from the previous join and the A object in memory, to verify that b3 and a2 have the same value.

These two rules, which produce the same result, have quite different computing costs.

  • The filter rule uses 155 pairs and a triple to represent the initial state, whereas the filter2 rule uses only 30 pairs and a triple.

  • Adding a C object costs 155 tests and the construction of a triple in the filter rule, whereas the same adding costs only 60 tests, a triple, and a pair in the filter2 rule.