Right now, in my drools project I have two groups of rules in separate DRL files which are split by agenda groups. For the agenda group "initial" I am setting auto focus to true for each rule in that agenda group.
rule "rule1"
agenda-group "initial"
auto-focus true
salience 50
when
// condition1
then
//
end
For the other agenda group - "final" - the rules do NOT have the auto focus attribute set. Example:
rule "rule2"
agenda-group "final"
activation-group "group1"
salience 0
when
// condition2
then
//
end
Below is the code snippet
val trigger(kieContainer: KieContainer) = {
val kieSession = kieContainer.newStatelessKieSession
val commands = new BatchExecutoinCommandImpl()
val agendaGroup = new AgendaGroupSetFocusCommand("initial")
val agendaGroup1 = new AgendaGroupSetFocusCommand("final")
executionCommand.addCommand(agendaGroup)
executionCommand.addCommand(agendaGroup1)
executionCommand.addCommand(CommandFactory.newInsert(customObject,
"obj"))
kieSession.execute(commands)
}
However, when the rules are executed, it seems like the rules in the "rule2" agenda group are being evaluated first. I have no idea why. I'm relatively new to drools, but I was sure this design would ensure the "rule1" rules would evaluate first.
I also had this "strange" behavior recently, but the Drools documentation explains that the agenda groups are managed with a stack:
Each time the setFocus() call is made in a Java application, the
Drools engine adds the specified agenda group to the top of the rule
stack
So with your current code, the "final" agenda group is given focus in first, since this is the last "AgendaGroupSetFocusCommand" you add in your command.
If you reverse the order of the "addCommand"s, you will have the expected behavior.
Related
I am using decision tables and would like to trigger one rule per input item.
I am using decision have set the Sequential = true and defined all rules as part of the same ACTIVATION-GROUP.
When I trigger the drools rules engine using below it just evaluates for the first input item and others are ignored. The behavior I want is to evaluate at most 1 rule per input item (rule order defined by the Salience).
kieStatelessSession.execute(inputList)
I can get this working by sending one item at a time to the kieStatelessSession, but would prefer to execute all at once.
I am using Drools verison 6.5.0.FINAL and Java 7.
There is no out of the box support in Drools for what you are trying to achieve. If you want your rules to be evaluated once for each fact, you will need to code it yourself.
One approach could be to have another type of facts to mark when one of the inputs is processed:
declare Marker
fact : Object
end
//Bellow are the rules that should be coming from your decision table.
//Each rule will do whatever it needs to do, and then it will create a
//Marker fact for the fact that was processed.
//These rules now include a "not" Conditional Element to avoid a fact to be
//evaluated more than once.
rule "Rule 1"
salience 100
when
$fact: Object(...) //your conditions
not Marker(fact == $fact)
then
//... Your logic
insert(new Marker($fact));
end
...
rule "Rule 50"
salience 50
when
$fact: Object(...) //your conditions
not Marker(fact == $fact)
then
//... Your logic
insert(new Marker($fact));
end
Hope it helps,
relative new comer to drools and rules engines.
I have three rules that essentially check if different instances of the same object exist, if they don't, they create one and insert it into the working memory. After performing a series of other related rules, theres a rule that checks for validity of the models.
The goal here is to have three different instances of the same object that represent three different entities and proceed as long as 2 of them are in a valid state.
They're defined as follows:
rule "SetupA"
salience 80
lock-on-active
when
not InvalidModel(name == "A-Name")
then
InvalidModel invalidA = new InvalidModel();
invalidA.setName("A-Name");
insert(invalidA);
end
rule "SetupB"
salience 80
lock-on-active
when
not InvalidModel(name == "B-Name")
then
InvalidModel invalidB = new InvalidModel();
invalidB.setName("B-Name");
insert(invalidB);
end
rule "SetupC"
salience 80
lock-on-active
when
not InvalidModel(name == "C-Name")
then
InvalidModel invalidC = new InvalidModel();
invalidC.setName("C-Name");
insert(invalidC);
end
rule "VALIDATE_MODEL_FOR_ANY_INVALID_FLAGS"
salience -10
when
$invalidList: List(size > 1) from collect(InvalidModel(isNotFound || isFlagged || isNotActive))
then
setDecision(result, "Denied");
end
However, what's happening is that it seems like these rules are matched on every request to this ruleset which I interpret as the facts not existing in the Working Memory. I'd expect the rules to be fired once, when each of the facts for the respective names dont exist, and then to not fire again as there is nothing that would remove them from the working memory. However, my audit log of the rules that fire show that for every request those rules get fired.
Furthermore, the fourth rule's condition seems to not be performing as expected as it returns a response like such
=============== DEBUG MESSAGE: illegal bytecode sequence - method not verified ================
My ask is for some guidance on where my logic/drools language structure may have gone astray. Thanks for your time.
I want to run a rule that calls Java method and passes the fact (or rather, its logical value) from another rule, although I don't know if the java methods are at all important for this problem. It's not easy to describe so I'll try to show it based on an example:
rule "Some rule determining fact"
when
... //some conditions
then
insert(new SomeCondition(callSomeJavaMethodReturningBoolean()))
end
rule "Some rule using SomeCondition"
when
SomeCondition($value: value)
... //some other conditions
then
insert(callJavaMethodUsingSomeCondition($value))
end
The problem here is that the first rule doesn't always fire, so SomeCondition is not always definded and second rule isn't evaluated.
My second try was to create two separate rules like this:
rule "Some rule determining fact"
when
... //some conditions
then
insert(new SomeCondition(callSomeJavaMethodReturningBoolean()))
end
rule "SomeConditionTrueRule"
when
SomeCondition(value == true)
... //some other conditions
then
insert(callJavaMethodUsingSomeCondition(true))
end
rule "SomeConditionFalseRule"
when
not SomeCondition() or SomeCondition(value == false)
... //some other conditions
then
insert(callJavaMethodUsingSomeCondition(false))
end
This doesn't work as intended either, because it first evaluates SomeConditionFalseRule before even evaluating my first rule. I'll appreciate any suggestions on how to solve this problem. Drools version used is 6.5.0 if that matters. Also, I want to avoid using salience if possible since I've read it is a bad practice (correct me if I'm wrong).
In this case, you need to separate the 2 groups of rules (the ones inserting SomeCondition objects and the ones executing the java code).
The easiest way would be to use a lower salience in the second group:
rule "Some rule determining fact"
when
... //some conditions
then
insert(new SomeCondition(callSomeJavaMethodReturningBoolean()))
end
rule "SomeConditionTrueRule"
salience -1
when
SomeCondition(value == true)
... //some other conditions
then
insert(callJavaMethodUsingSomeCondition(true))
end
rule "SomeConditionFalseRule"
salience -1
when
not SomeCondition() or SomeCondition(value == false)
... //some other conditions
then
insert(callJavaMethodUsingSomeCondition(false))
end
A more robust approach would be to use 2 agenda-groups and to activate them one after the other.
But the idea is that the rules executing the java code give time to the rules determining what needs to be executed to come up with the final decision.
In the case I've presented above, as soon as you create your session, you will have an activation (A1) for SomeConditionFalseRule but the activation will not be executed until you call fireAllRules(). If you then insert the necessary facts to make SomeConditionTrueRule true, you will have now an activation (A2) for it.
At this point, the agenda will look like this: | A1 | A2 |.
When calling fireAllRules(), Drools will pick the activation in the agenda with the higher salience (by default, rules have a salience of 0). In this case, A2 will be picked and executed.
The execution of A2 will insert a new Fact that will make A1 invalid and it will create a new activation (A3) for SomeConditionTrueRule. Drools will then proceed to remove A1 from the agenda, so the rule SomeConditionFalseRule will not be executed.
The agenda after A2 is executed will look like this: | A3 |
Hope it helps,
I would like to setup a rule to have more than one rule flow group. The reason for this is that I will have different BPMN processes which will take different subset of rules depending on their rule flow group. For example,
rule "Test 1" ruleflow-group "A" ruleflow-group "B"
when
// Condition
then
// Action
end
rule "Test 2" ruleflow-group "A"
when
// Condition
then
// Action
end
BPMN Process 1 is linked to ruleflow-group A, so it should run rules Test 1 and Test 2.
BPMN Process 2 is linked to ruleflow-group B, so it should run rule Test 2 only.
When I write rules as above, the compiler does not complain. However, when running BPMN Process 1, it only runs rule Test 2. When running BPMN Process 2, it only runs rule Test 1.
Rule class definition in jboss drools source code has a single String field for ruleflow-group attribute. So it is not possible for one rule to have multiple ruleflow groups.
public void setRuleFlowGroup(final String ruleFlowGroup) {
this.ruleFlowGroup = ruleFlowGroup;
}
Alternatively you can use control facts to group your rules.
rule 1
when
Controller(group in ("group1", "group2"))
then
...
As an exercise in teaching myself drools I'm working on rules for bidding in the bridge card game. The rules work independently of each other (enforced by use of drools.halt() in the rules) but when I try to extend the example by removing the halt() calls, I get behavior I didn't expect. In the example below I am commenting out the halt() in the first rule, and adding the size() condition to the 2nd rule to replace it, trying to prevent the 2nd rule from firing. I would not expect the 2nd rule to fire because the consequence of the first rule added a bid to the Auction's collection, and so subsequently in rule 2 the count should not be zero. I've tried explicitly adding the 'update' or 'modify' directives in the first rule, but that didn't make any difference.
rule "rule1"
salience 100
when
$auction : Auction( $currentBidder : currentBidder != null )
$hand : Hand( owner.equals($currentBidder), getTotalPoints(getLongestSuit()) >= 13 )
then
$auction.bid($currentBidder, new Bid(1, $hand.getLongestSuit()));
//drools.halt();
end
rule "rule2"
salience 1
when
$auction : Auction( $currentBidder : currentBidder != null, getPlayerBids().size() == 0 )
Hand(owner.equals($currentBidder))
then
$auction.bid($currentBidder, new Pass());
drools.halt();
end
When you change an object, you need to tell the engine you updated it. So try adding update($action); at the end of the first rule.