Alex
Alex

Reputation: 101

Working Memory & objects insertion behavior in Drools

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.

Upvotes: 2

Views: 8621

Answers (2)

laune
laune

Reputation: 31300

Here's a blow-by-blow account of what happens, with annotations to show where to find the answers to Q1, Q2 and Q3. Lines starting with '!' are statements in your Java or DRL code, as executed, a '#' indicates a comment by me and other lines are output.

! fact1 = kSession.insert(new Counter(1) );
# "Counter shower 1" matches; an activation binding $Counter to the inserted
# fact1 is created
# "Counter shower 2" matches; an activation binding $Counter to the inserted
# fact1 is created
# "Counter shower 3" matches; an activation with the inserted fact1
#  is created
! kSession.fireAllRules();
# The Agenda contains three activations; the consequences of these rules are
# executed
Counter there (1) : 1
Counter there (2) : 1
Counters there (3) 
! fact2 = kSession.insert(new Counter(2) );
# "Counter shower 1" matches; an activation binding $Counter to the inserted
# fact2 is created
# "Counter shower 2" matches; an activation binding $Counter to the inserted
# fact2 is created
# The accumulate changes as it now accumulates two Counter facts; therefore
# another activation is created with $Counter being bound to fact1, which
# is still (half-cocked) bound to this rule; the activation is completed due
# to the change in the accumulate.
# "Counter shower 3" matches; an activation with the inserted fact2
# is created
# Nothing has happened with fact1, so there is (by definition) no reason to
# recreate activations in relation to fact1. (Q1, Q2)
# With a Counter(2) present, also "Counter creator" is activated and put on
# the agenda.
! kSession.fireAllRules();
Counter there (1) : 2 
Counter there (2) : 1 
Counter there (2) : 2 
Counters there (3)
new Counter created
! insert( new Counter(3) );
# "Counter shower 1" matches; an activation binding $Counter to the inserted
# fact3 is created
# "Counter shower 2" matches; an activation binding $Counter to the inserted
# fact3 is created
# The accumulate changes as it now accumulates three Counter facts; therefore
# another activation is created with $Counter being bound to fact1 and also
# to fact2, both of which are still (half-cocked) bound to this rule; the
# activation is completed due to the change in the accumulate. (Q3)
# "Counter shower 3" matches; an activation with the inserted fact2
# is created
# Nothing has happened with fact1 and fact3, so there is (by definition) no
# reason to recreate activations in relation to rules simply matching fact1 
# and fact2. (Q1, Q2)
# With a Counter(1) and a Counter(3) present, "Counter remover" is activated
# and put on the agenda.
Counter there (1) : 3 
Counter there (2) : 1
Counter there (2) : 2
Counter there (2) : 3
Counters there (3)
retract counter with ID = 1
# We have the three half-cocked activations of "Counter shower 2", where the
# set of accumulated Counter facts changed due to the retraction of
# Counter(1). The one with this Counter being bound to $Counter is a goner
# now, but the other two are reactivated with a shortened list of Counter
# facts to be counted.
Counter there (2) : 2
Counter there (2) : 3

Upvotes: 1

Steve
Steve

Reputation: 9480

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.

Upvotes: 3

Related Questions