When a rule becomes too complex or it comprises of multiple complex conditions, defining them in one single rule might not be the best way to go. In imperative programming (such as Java and C++), we would break down a method or function, which is complex, into many smaller, simpler methods. In Drools, we should follow a similar structure defining multiple, simpler rules that work together.

Due to the nature of declarative programming that the DRL language follows, we cannot call one rule from another one, therefore, this splitting has to be done differently. To be able to split our rules into simpler ones, the actions of a rule requires to add or modify data so that other rules will re-evaluate themselves against the data and see if they should trigger their actions or not.

insertLogical keyword

In the then part of our rules, new information might be inferred by a rule. More data can be made available to the working memory for further evaluations against all the rules using the insertLogical keyword, as follows:

rule "Classify Customer - Gold"
    when
        $c: Customer( category == Customer.Category.GOLD )
    then
        insertLogical (new IsGoldCustomer($c));
end

rule "Classify Item - Low price"
   when
      $i: Item(cost < 10.00)
   then
      insertLogical (new IsLowRangeItem($i));
end

rule "Suggest gift"
   when
      IsGoldCustomer($c: customer)
      IsLowRangeItem($i: item)
   then
      System.out.println("Suggest giving a gift of item "+$i.getName()+" to customer +"$c.getName());
end

We’re breaking down the rule in three parts and inserting new model elements (IsGoldCustomer and IsLowRangeItem) to let another rule make the main decision for us based on these two elements.

By breaking down the rule in smaller sections, having some rules in charge of determining what a gold customer is and other rules in charge of what to do with them, we can define a gold customer in many different ways. Later on, all the rules have to rely on the IsGoldCustomer fact and any extra condition to determine what to do.

In fact there are 2 keywords to insert elements: insertLogical and plain insert. The difference is in the element Lifecycle Management. In case of insertLogical automatic lifecycle management is turned on, meaning that the element will be automatically deleted from the memory when rule’s when condition does not hold anymore. As a result, use of insert keyword is discouraged in favor of insertLogical.

modify and update keywords

We can also take the already existing data, which might have triggered the condition of a rule, and notify the engine should re-evaluate it. This can be done using the modify keyword, as follows:

rule "Categorize Customer - Gold"
  when
    $c: Customer( category == Customer.Category.NA )
    $o: Order(customer == $c, orderLines.size() > 10)
  then
    modify($c) {setCategory(Customer.Category.GOLD);}
end

This rule is modifying the Customer object to set it to gold category. After this modification, the engine will be notified that this object needs to be re-evaluated for all rules in the engine. This means that if we insert a Customer with no category and an Order on its name with over 10 items, it will not only set the corresponding category, but also trigger any rule that depends on this condition.

Another word that you can use instead of modify in the consequence of the rule is the update keyword. The update keyword does not take a code block as the modify keyword. Instead, it just receives a variable so that the modifications have to be done beforehand to the variable. The following code example would replace the modify keyword in the previous code section, as follows:

$c.setCategory(Customer.Category.GOLD);
update($c);

However, the use of update is discouraged in favor of modify blocks as they allow to syntactically group the fact’s execution that should trigger rule re-evaluations.

As you can see, the modification of the working memory is essential to split a rule into multiple ones as all the rules will be triggered depending—at first—on the data that the engine has available. By modifying the data, the engine can continue triggering rules until no more rules match the available data. If we don’t modify/update the data, the engine will not be able to see the changes that you may do in a fact and this object won’t trigger any more rules than the ones that had already matched before the change.

delete/retract keywords

In case insert was used to insert an element into the memory, it has to be removed using delete or retract. Both valid to remove the objects from the working memory—though the retract keyword is deprecated. Their syntax is equivalent and they are mutually exchangeable in the DRL code.