Drools Core DRL - Fire only one rule with the highest salience, skip other rules

user3430447 picture user3430447 · Mar 17, 2014 · Viewed 17.9k times · Source

I have simple JAVA bean with two int fields: 'a' and 'b'.

I have two rules:

rule "First rule"
salience 10
when
    $bean : Bean ( a == 1)
then
    $bean.setB(10);
end

rule "Second rule"
salience 20
when
    $bean : Bean ( a == 1)
then
    $bean.setB(20);
end

Actual results: "Second rule" is fired first (higher salience), "First rule" is fired second.

Expected results: Only one rule (with the highest salience) is fired. Other rules are ignored. How to do this? Is it possible in Drools? I am using Drools 6.0.0 Final.

Requirements: 1. I can't use 'activation-group'. 2. I don't want to use 'retract' on each bean.

UPDATE

Really thanks for your answers.

Probably I should describe my problem in details. I have a set of 1500 rules. Each rule:

  • works with the same bean - this bean has a lot of fields (properties),
  • has salience,
  • has a lot of conditions,
  • has only one action - setting one (always the same) boolean flag in my bean.

What I want to get? When I have conflict (the input fact is matched by two or more rules) I want to fire only one rule with the highest salience. Other matched rules for this one fact should be ignored. The most important thing is performance - this should work as fast as possible.

What I do? At the moment I have two solutions but I don't know which one is better or maybe I should solve this problem in different way.

Solution 1 - Statefull session

Java code:

for (Object fact : facts) {
    FactHandle fh = session.insert(fact);
    session.fireAllRules(1);
    session.delete(fh);
}

Solution 2 - Stateless session

Java code:

for (Object fact : facts) {
    session.execute(fact);
}

DRL file for solution 2: I added to each rule the same activation-group:

rule "Rule"
activation-group "group"
salience X
when
    ...
then
    ...

Answer

melchoir55 picture melchoir55 · Mar 17, 2014

Based on your question, I'm worried you might be misunderstanding the point of salience. Salience is a prioritization value. Drools uses it in order figure out which drool to fire first when it is the case that the constraints for more than one rule are satisfied.

The problem of [firing rule P under certain circumstances and NOT rule Q when rule P is fired] is a common one. Your object model should be set up such that this is a natural consequence of reasoning over your concept space. For the literal situation you have listed, you might try inserting a new fact into working memory ("RuleFiredFact" with a value of "2nd", or whatever). You would then check for this fact in your first rule constraints. If it is true, the first rule doesn't fire.

UPDATE: To be clear, "RuleFiredFact" is an abstract placeholder for some concrete fact in your fact model. Part of the point of drools is not using abstract stuff in the drools DSL.

UPDATE:

Whether or not stateful vs. stateless session is appropriate is going to depend a lot on your available computer resources, object model, team, the list goes on. If you don't know which to use, you should refer to a discussion on the topic. You might try this older mailing list post http://drools.46999.n3.nabble.com/Advice-sought-on-choosing-Stateful-or-Stateless-sessions-td57069.html

Whichever you go with, I strongly suspect your object model is too shallow. It is very uncommon to create a drools system which contains one fact, then never creates any more. The point of drools is to reason over a number of facts. The way to tackle this is probably going to be something like moving through your object and inserting the information within it into the drools working memory as facts. You would then write rules which only fire under the constraints you want.

In a circumstance like what I describe, there are many ways of making sure only a single rule fires. Your rules may all be on the lookout for a "factWasAlreadyReasonedOverFact" with a reference to the fact which triggered the execution. This is a pretty rough example. Hopefully it gives you an idea.