1

I have two rules

rule "test1"
    when
        $cr: MyContext(flag1 == 1)
    then
        System.out.println("<---- Test1 start ---->");
        $cr.setFlag1(10);
        System.out.println("<---- Test1 end ---->");
    end
rule "test2" salience -1
    when
        $cr: MyContext($flag1: flag1 == 1)
    then
        System.out.println("<---- Test2 start ---->");
        System.out.println($flag1);
        System.out.println("<---- Test2 end ---->");
    end

I rule1, I am checking if the variable MyContext.flag1 is 1. Since it's true I am changing it to 10. I rule2, I am checking if the variable MyContext.flag1 is 1. I didn't expect this rule to execute as flag1 is 10.

But surprisingly, it executes and prints flag1 as 10.

How is it evaluating flag1 == 1 as true in the LHS of rule2 and in the RHS printing flag1 as 10?

Prajwal
  • 563
  • 7
  • 22

2 Answers2

2

When you fire drools rules, what happens is that the framework takes your rule inputs in working memory and determines which rules match. These rule matches are then ordered (either by salience or the natural order) and then fired sequentially.

So when you fire your rules, "test1" and "test2" are determined to be matches. Then Drools goes on to fire "test1" first, followed by "test2".

If you want Drools to reevaluate the rule matches, you need to "tell" the framework that you have made changes to working memory. To do this, you have the following built-in methods:

Method Explanation
insert Put a new fact into working memory.
delete or retract Removes some information (object/s) from working memory.
update Update/replace a fact in working memory.
modify Change fields inside of a fact in working memory.

There are also some "logical" versions of these methods which you can read more about in the Drools documentation.

If you don't use these built-in framework methods when or after making your change, you're going to keep evaluation the initial set of rule matches. Those changes are effectively invisible to drools, because you haven't told Drools "hey we've made changes." The left hand side of each rule has been evaluated against the original set of data; the right hand side is evaluated sequentially based on matches.

So in your case, what you want to do is to use the modify function to tell Drools that you're applying changes to a piece of information in working memory.

rule "test1"
when
  $cr: MyContext(flag1 == 1)
then
  modify( $cr ) {
    setFlag1(10)
  }
end

One thing to pay attention to is how the rule matches are evaluated. When you call insert to put a new piece of data into working memory, Drools will do a partial re-evaluation of rule matches. Rule that have already been matched and executed will not be run again; only subsequent rules are reevaluated to figure out if they now match.

In contrast, update will do a full evaluation of all rules. It's the functional equivalent of stopping the current rule execution and calling fireAllRules with the new data in working memory.

If you have rules that have external side effects or are not idempotent, calling update may have serious side effects because you will potentially be evaluating the RHS of a rule multiple times as the data changes.

Roddy of the Frozen Peas
  • 14,380
  • 9
  • 49
  • 99
1

Initially, Drools evaluates that two rules must be fired according to the facts in your working memory. So the agenda of the rules to be fired is (according to your salience) :

  • Rule "test1" waiting to be fired ...
  • Rule "test2" waiting to be fired ...

What you miss is that the agenda is not modified if you do not say Drools so. In your case rule "test1" is fired, then it is removed from the agenda, and the new state of the agenda is :

  • Rule "test2" waiting to be fired ...

So what happens next, the rule "test2" is fired, and since you changed your fact, drools print its new value, which is 10. So the behaviour is ok.

What you need is to call update($cr) after you modified it in the rule "test1", which means : update the agenda with all the rules depending of my fact $cr. The consequence is Drools is going to remove the rule "test2" from its agenda now.

Chaudusse
  • 11
  • 1