Working Memory & objects insertion behavior in Drools

Alexander K picture Alexander K · Oct 17, 2014 · Viewed 7.5k times · Source

A am new in Drools and have read some docs and tutorials, sure, my question has a trivial solution. I use onle rule file and class Counter, depicted below. The environment is : Wintel JDK 1.7 (71), DROOLS 6.1.0

public class DroolsInsertionTester {
private Logger log = Logger.getLogger(this.getClass().getName());

private KieSession getNewStatefullKIESession (){
   KieContainer kContainer = KieServices.Factory.get().getKieClasspathContainer();

   KieSession kSession = kContainer.newKieSession("test");
   return kSession;
}
public static void main(String[] args) {
    // TODO Auto-generated method stub
    DroolsInsertionTester tester =  new DroolsInsertionTester();
    tester.test(); 


}

private void test() {
    KieSession kSession = getNewStatefullKIESession();

    Counter cnt1 = new Counter(1);
    Counter cnt2 = new Counter(2);

    FactHandle fact1, fact2;

    // STEP 1
    fact1 = kSession.insert(cnt1);
    kSession.fireAllRules();

    // STEP 2
    fact2 = kSession.insert(cnt2);
    kSession.fireAllRules();
}

 public class Counter {
      public int count;
      public Counter (int cnt){
           this.count = cnt;
 }

there is an rule

 rule "Counter shower 1" 
    when $Counter  : Counter() 
 then 
    System.out.println("Counter there (1) : " + $Counter.count);
 end

 rule "Counter shower 2" 
when 
    $Counter  : Counter()  
    accumulate (Counter() ; $cnt : count())
then 
    System.out.println("Counter there (2) : " + $Counter.count);
end 

rule "Counter shower 3" 
when 
    Counter()  
then 
System.out.println("Counters there (3) : ");
end 

rule "Counter creator" 
    when $Counter  : Counter(count == 2) 
then 
    insert (new Counter(3)); // STEP 3
     System.out.println("new Counter created ");
end

rule "Counter remover" 
    when 
    $Counter  : Counter(count == 1)
    exists Counter (count == 3) 
then 
    retract ($Counter) ; // STEP 4
     System.out.println("retract counter with ID = 1");
end

This is kModule

<?xml version="1.0" encoding="UTF-8" ?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
<kbase name="rules" packages="rules">
        <ksession name="test" />
 </kbase>
</kmodule>

The result of runnings

Counter there (1) : 1
Counter there (2) : 1
Counters there (3) : 
Counter there (1) : 2
Counter there (2) : 1
Counter there (2) : 2
Counters there (3) : 
new Counter created 
Counter there (1) : 3
Counter there (2) : 1
Counter there (2) : 2
Counter there (2) : 3
Counters there (3) : 
retract counter with ID = 1
Counter there (2) : 2
Counter there (2) : 3

My questions are:

  1. The program code doesn’t contain any “kSession.delete” all fact are hold in Working memory. So, in my point of view, the rules "Counter shower 1" .. "Counter shower 3" should fire for each Counter object in Working Memory after each fireAllRules calls. One for STEP 1, two times for STEP2, three times for STEP3 e.g. But output listing notes only "Counter shower 2" worked in that way. The "Counter shower 1" and "Counter shower 3" fire only once by one fireAllRules call.

  2. Why rule "Counter shower 1" catches over last inserted facts only? Are any hidden behaviors there?

3.Why after retract object Counter with count == 1 only "Counter shower 2" fires? What about other rules ?

Thank for any help.

Answer

Steve picture Steve · Oct 17, 2014

Question 1: The program code doesn’t contain any “kSession.delete” all fact are hold in Working memory. So, in my point of view, the rules "Counter shower 1" .. "Counter shower 3" should fire for each Counter object in Working Memory after each fireAllRules calls. One for STEP 1, two times for STEP2, three times for STEP3 e.g. But output listing notes only "Counter shower 2" worked in that way. The "Counter shower 1" and "Counter shower 3" fire only once by one fireAllRules call.

You should understand that fireAllRules doesn't actually fire all of the rules in your knowledge base. The name is a bit misleading. :)

Instead of talking about rules "firing", it's better to thing of them as "activating". You have a stateful session, so when you first called fireAllRules, three of your rules activated based on the Counter you initially inserted. When you call insert/fireAllRules again, those rules are still activated for the initial Counter! They do not need to activate again. Unless the state of the working memory has changed to cause a rule to deactivate and reactivate, you will not see anything happening in your right-hand-sides.

This is actually the whole point of a stateful session. Your knowledge base can incrementally "learn" facts and can evaluate new facts based on existing knowledge.

Evaluating every fact from the assumption of zero knowledge is what stateless sessions are for.

Question 2: Why rule "Counter shower 1" catches over last inserted facts only?

You have a stateful session, so the match for the initial insert of a Counter activated on the first fireAllRules. Nothing has changed in working memory since then to impact the initial activation, so it no longer needs to activate when you fireAllRules again.

Question 3: Why after retract object Counter with count == 1 only "Counter shower 2" fires? What about other rules?

The "Counter shower 2" rule is the only rule affected by the retraction, because it has an accumulator counting your Counter facts.