user3430447
user3430447

Reputation: 51

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

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:

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
    ...

Upvotes: 5

Views: 21556

Answers (5)

Neeraj_Nitd
Neeraj_Nitd

Reputation: 11

You can use drools.halt(); in your highest salience rule.

What this do is it terminate the flow and come out of rule execution (exactly what you need).

Upvotes: 1

GauRang Omar
GauRang Omar

Reputation: 871

One solution you can try is the "lock-on-active" attribute to avoid infinite execution loops involving one or more rules.

Lock-on-active is scoped by a rule-group and will prevent rules from re-firing as long as the group is focused. It does not depend on new facts, or updates to the existing ones, but only on the agenda focus. If you do not manipulate groups, this may be an option.

Upvotes: 0

Shervin Asgari
Shervin Asgari

Reputation: 24517

I would solve this using activation-group with salience as you have described in Solution 2

Upvotes: 0

melchoir55
melchoir55

Reputation: 7286

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.

Upvotes: 5

Esteban Aliverti
Esteban Aliverti

Reputation: 6322

First of all let me tell you that you have some weird scenario right here :)

There are multiple solutions for this problem:

  • Use another attribute of Bean class to mark already 'processed' facts.
  • Use a custom AgendaFilter
  • Use ksession.fireAllRules(1);

Hope it helps,

Upvotes: 1

Related Questions