Drools Update, Modify Infinite Loop Execution-Resolved - Java @ Desk

Friday, December 13, 2013

Drools Update, Modify Infinite Loop Execution-Resolved

Drools Update, Modify Infinite Loop Execution
When we use update or modify in a DRL file, we fall into the infinite looping issue many number of times.
There arise a case where the update or modify need to get called so that other rules can use the modified value.

But as soon as we update the fact, it either
1) Activates the rule itself
2) Activates other rules that may eventually reactivate the original rule.

Consider first scenario, where the update operation activates the same rule and rule enters in an infinite loop
rule "Rule One"
agenda-group "Name Field"
salience 90
    when
  $pojo : Pojo(name == "Kumar" || address=="Mumbai")
    then
        System.out.println("Rules Name is - " + drools.getRule().getName());
        $pojo.setAddress("Mumbai CST");
        update($pojo);
end

Pojo pojo = new Pojo();
pojo.setName("Kumar");
ksession.insert(pojo);

Look at the example above, before firing the rule, name field is set to "Kumar" and the rule checks condition on name and address field. If any condition satisfies update the address and perform drools update on pojo object. As soon as update happens, it will re-activate the same rule and as you can see it enters into an infinite loop.

To avoid this, we need to use lock-on-active keyword for the rule. lock-on-active avoids activation of the rule within the agenda-group even if update or modify operations takes place.

One more thing on lock-on-active is, if any of the rule consequence updates the value of any field, that update will not get reflected within that agenda-group. The updated values gets visible once the current agenda group rund out of focus. Look at the below example for the same.
rule "Rule Two"
lock-on-active 
agenda-group "Name Field"
salience 90
    when
  $pojo : Pojo(name == "Kumar" || address=="Mumbai")
    then
        System.out.println("Rules Name is - " + drools.getRule().getName());
        $pojo.setAddress("Mumbai CST");
        $pojo.setName("Bhatia");
        update($pojo);
end

rule "Rule Two"
lock-on-active 
agenda-group "Name Field"
salience 85
    when
  $pojo : Pojo(name == "Bhatia")
    then
        System.out.println("Rules Name is - " + drools.getRule().getName());
        $pojo.setName("Kumar");
        update($pojo);
end

As shown above, the name field is set to "Bhatia" in the first rule but the update is not getting reflected within that agenda. If it could have hapenned, second rule also would have fired.

In this way, we avoid the looping issue by using the lock-on-active.
If you will use no-loop, it will stop looping of the rule where the update happens but it will activate other rules in the same agenda and so we fall back to infinite loop issue.

If there is a requirement where the updated value of the facts need to be used in the other rules then
1) Keep the second rule in the next agenda.
2) Activate that agenda once the first rule got fired.

Look at the below implementation:

KnowledgeBase kbase = readKnowledgeBase();
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");
Pojo pojo = new Pojo();
pojo.setName("Kumar");
ksession.insert(pojo);
ksession.getAgenda().getAgendaGroup("Name Field Update Check").setFocus();
ksession.getAgenda().getAgendaGroup("Name Field").setFocus();
ksession.fireAllRules();
logger.close();

rule "Rule One"
lock-on-active 
agenda-group "Name Field"
salience 90
    when
  $pojo : Pojo(name == "Kumar" || address=="Mumbai")
    then
        System.out.println("Rules Name is - " + drools.getRule().getName());
        $pojo.setAddress("Mumbai CST");
        $pojo.setName("Bhatia");
        update($pojo);
end



rule "Rule Two"
lock-on-active 
agenda-group "Name Field"
salience 85
    when
  $pojo : Pojo(name == "Bhatia")
    then
        System.out.println("Rules Name is - " + drools.getRule().getName());
        $pojo.setName("Kumar");
        update($pojo);
end

rule "Rule Three"
lock-on-active 
agenda-group "Name Field Update Check"
salience 70
    when
  $pojo : Pojo(name == "Bhatia")
    then
        System.out.println("Rules Name is - " + drools.getRule().getName());
        $pojo.setName("Kumar");
        update($pojo);
end

As shown above, Rule Three & Rule Two uses the updated value of name field in then part. But since, Rule Two is within same agenda as of Rule One, the updated values does not gets reflected for Rule Two. Since, Rule Three is in different agenda "Name Field Update Check" that gets activated after agenda "Name Field" the value of updated name field gets reflected for the Rule Three.






No comments:

Post a Comment