Search code examples
javadrools

how to write rules for same type of facts sequentially?


We are trying to write rules for same type of objects . There are objects of typeA having property valid=true ,valid=false,valid=NA. The condition is we want to fire rules in sequence such that

facts valid=="true" && space=="true" if it doesn't gives output for all provided facts then it should go to next rule facts valid=="NA" && space=="true" if any of the provided facts doesn't give output then only we want to go 3rd rule facts valid=="false" && space=="true" .

If first rule it self gives output then we don't want to go to next rule .

our code snippet looks like:

**TypeA a =new TypeA();
a.setValid("true");
a.setSpace("false");

TypeA b = new TypeA();
b.setValid("true");
b.setSpace("true");

TypeA c=new TypeC();
b.setValid("NA");
b.setSpace("true");

TypeA d=new TypeC();
d.setValid("false");
d.setSpace("true");
List<TypeA> typeAList=new ArrayList<>();
typeAList.add(a);
typeAList.add(b);
typeAList.add(c);
typeAList.add(d);**

//code for creation of KieBase

**kieBase.newStatelessKieSession().execute(typeAList);**

**rule "5"
salience 5
when
    $typeA: TypeA(valid=="true" && space=="true")
then
System.out.println("location found at A");
end

rule "4"
salience 4
when
    $typeA: TypeA(valid=="NA" && space=="true")
then
System.out.println("location found at B");
end

rule "3"
salience 3
when
    $typeA: TypeA(valid=="false" && space=="true")
then
System.out.println("location found at C");
end**

We want output as only "location found at A" as one of the facts passes this condition . but it's returning output as "location found at A","location found at B","location found at C"


Solution

  • Do keep in mind that the main point of a rule engine is to match facts against rules and then fire all the relevant ones. In your case all the rules can fire since you add all 4 facts to the working memory. First rule finds the matching fact b and fires, second rule finds the matching fact c and fires, and finally the third rule finds the matching fact d and fires. This is all intended behaviour. That said, I do see two potential ways to solve that issue :

    1) You can add a condition in the second rule about not finding any fact that matches the first rule. Your LHS would look like this :

    when
        $typeA: TypeA(valid=="NA" && space=="true")
        not (exists (TypeA(valid=="true" && space=="true")))
    

    This will work, but depending on how many rules you want to write this way, this can quickly become cumbersome to do.

    2) You could use ruleflow-groups to fire your rules in a more controlled way. In your case, each rule would be in its own group, and at the end of a group's execution you could check a boolean fact (you can create facts on primitive types) that is modified by the first rule to determine whether to finish the execution or go to the next group. You could also do the same with agenda-groups instead and place the "intelligence" of the algorithm in the main program instead of in the ruleflow. (still needs the boolean facts for this)

    Hope this helps.