0

We are using drools rule engine 5x We have a rule configured like

Fact {A,B,C}, Action [X] Fact {A,B}, Action [Z]

When I pass {A,B,C} I am getting both actions [X],[Z]. Is it expected behaviour from drools engine? Can it be possible to define C as optional fact, in which case, can this be possible?

saiD
  • 19
  • 1
  • 7

2 Answers2

2

This is working correctly. Both rules meet the conditions to fire, so both rules do fire.

If you don't want the AB rule to fire when the C condition is passed, you need to write it so that it explicitly doesn't trigger.

Here's an example:

rule "ABC"
when
  A()
  B()
  C()
then
  System.out.println("ABC");
end

rule "AB not C"
when
  A()
  B()
  not( C() )
then
  System.out.println("AB not C");
end

In this example, if you pass objects A, B, and C into the rules, only the first rule will fire because the second rule is mutually exclusive: it will only trigger when C is not present. Similarly, if you only pass A and B in, but not C, then only the second rule will fire because the first rule requires C and the requirement is not met.

Without the not( C() ) condition, you'd have what you have in your example: the rule will fire regardless of the presence (or abscence) of the C object in memory because it is entirely irrelevant. You ask if you can make C optional -- as you have it, C is optional. If it is present or not does not matter.


Note that exactly how you negate condition "C" depends on what it actually is. If your fact was instead like this: MyObj( a == 1, b == 2, c >= 3), then you'd negate C by having the AB rule key on: MyObj( a == 1, b == 2, c < 3). You simply need to invert the "C" condition check, whatever it is.


For completeness sake, it's worth mentioning that you can modify the items in working memory in order to keep the second rule from firing after the first does. If these two rules live in a vacuum, this might bee the solution for you; if they're a part of a larger rule set there are likely other rules depending on these same facts which might cause unintended consequences.

Firstly, you can insert a "flag" into working memory and key off of its presence (or lack thereof) in the rule you don't want to trigger. So if you don't want AB to trigger if ABC was triggered you can insert a flag on the right hand side of the ABC rule:

declare Flag
  name: String
end

rule "ABC with flag"
when
  A()
  B()
  C()
then
  Flag f = new Flag();
  f.setName("ABC");
  insert( f )
end

rule "AB but not if ABC"
when
  A()
  B()
  not( Flag(name = "ABC" ))
then
  //...
end

Here, rule ABC inserts a flag when it fires; rule AB checks for the presence of the flag before firing.

Alternatively you can retract facts from working memory, so that rules which require that data no longer trigger. This potentially has wide-reaching consequences (data is actually removed from working memory so when Drools reevaluates all rules for being valid you might trigger unexpected ones) so it's generally not recommended that you do this.

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

This behavior is the one expected. It seems that what you'd like exactly is something like : if Rule1 Fact(A,B,C) and Rule2 Fact(A,B) are true together , then only Rule1 Fact(A,b,C) triggers.

This is like rule overriding. It is not possible as-is with #drools. It is possible with other tools, like #ibmodm.

I guess the easier way to write what you'd like to do is to write : Fact(A,B and not C) Action Z for Rule1.

Hope this helps, Emmanuel

Emmanuel B.
  • 226
  • 2
  • 7
  • To see an example of rule overrriding in IBM ODM see https://stackoverflow.com/questions/9602572/rule-overriding-in-ilog-jrules-rule-studio?rq=1 – Emmanuel B. Nov 28 '22 at 08:13
  • 1
    Actually there is a similar concept in Drools - it is called activation groups: https://docs.drools.org/8.31.0.Final/drools-docs/docs-website/drools/rule-engine/index.html#_activation_groups_for_rules. Writing this to just highlight the feature. The correct answer for the question is using not C in a rule in my opinion. – Tibor Zimányi Dec 06 '22 at 11:09