Where can I see if a pattern failed in rule? - drools

I run a rule that contains a few patterns, I want to know which pattern failed:
I've tried to debug the code (drools 7.18.0), and didn't found the relevant place.
rule example:
rule "Trigger"
agenda-group "Trigger"
salience 100
when
$pcase : PCaseMgr()
D1($id: id, type != null, type == "AAA")
D2(aId == $id)
then
$pcase.printAnalyticsRuleLog(">>>>>>>>>>>>>>>>>>> In Trigger");
end
in the example above, if D1 pattern is passed, and D2 pattern is failed, where in the code (of drools 7.18.0) can i see if the pattern was failed?

You can't. Because of the algorithm Drools uses internally, patterns are decomposed into nodes and nodes can be shared among multiple rules in your knowledge base. If you really need to know why a rule was not fire, then you can create other rules that will tell you that. In your example, you could create something like this:
rule "No Trigger because of No D2"
agenda-group "Trigger"
salience 100
when
$pcase : PCaseMgr()
D1($id: id, type != null, type == "AAA")
not D2(aId == $id)
then
$pcase.printAnalyticsRuleLog(">>>>>>>>>>>>>>>>>>> No Trigger because no D2");
end
Hope it helps,

Related

Getting value from WHEN part while a condition meets using EXISTS keyword in drools

rule "attaching AV and impact rating"
agenda-group "evaluate likelihood"
dialect "java"
when
Application($threatList:getThreatList())
$av:AttackVector()
exists $threat:Application.Threats(impact == "Disclose Information")from $threatList
exists AttackVector($av == AttackVector.REQUEST_MANIPULATION)
then
RiskRating riskRating=new RiskRating($threat.getImpactRating(),$av.getLikelihood(),$av.getName());
insertLogical(riskRating);
end
I am working on getting the object $threat in THEN part of the above-mentioned rule. If I run the above rule, it says:
Rule Compilation error : [Rule name='attaching AV and impact rating']
referee/security/attack/Rule_attaching_AV_and_impact_rating1426933818.java (7:1053) : $threat cannot be resolved
If I loop through it and get the value in the THEN part, it causes a CARTESIAN product and inserts the values a number of times in the session. My rule looks like this when I get the cartesian product.
rule "attaching AV and impact rating"
agenda-group "evaluate likelihood"
dialect "java"
when
Application($threatList:getThreatList())
$av:AttackVector()
exists $threat:Application.Threats(impact == "Disclose Information")from $threatList
$threat:Application.Threats(impact == "Disclose Information")from $threatList
exists AttackVector($av == AttackVector.REQUEST_MANIPULATION)
then
RiskRating riskRating=new RiskRating($threat.getImpactRating(),$av.getLikelihood(),$av.getName());
insertLogical(riskRating);
end
How do I get the value of $threat in THEN part without having the cartesian product?
Remove the exists operation entirely.
rule "attaching AV and impact rating"
agenda-group "evaluate likelihood"
dialect "java"
when
Application($threatList:getThreatList())
$av: AttackVector()
$threat: Application.Threats(impact == "Disclose Information")from $threatList
exists(AttackVector($av == AttackVector.REQUEST_MANIPULATION))
then
RiskRating riskRating=new RiskRating($threat.getImpactRating(),$av.getLikelihood(),$av.getName());
insertLogical(riskRating);
end
exists means "there is a thing in working memory that matches these conditions/looks like this". It's not used to actually extract or provide a reference to that matching instance. Simply remove the operator and it works as you need -- if there is an Application.Threats that matches your conditions, the rule triggers and the matching value is assigned to the $threat variable.
What you're running into is the fact that you have multiple threats that mean your condition, which is why you're having multiple triggers of the rule -- it will trigger once per matching Application.Threats. The exists keyword mitigates this because it only cares that at least one match exists, but you don't get a reference (because if there's four matches which one will be assigned to the variable? it doesn't make sense, logically.)
So you need to change your rule so that it won't fire multiple times and will instead only fire once when it finds a match. Usually you'd do this by making the consequences do something to working memory that makes the rule no longer eligible to be fired. In your example, you insert a RiskRating object; you could, then, check that no risk rating exists in your conditions:
not( RiskRating( /* insert criteria here or leave empty */ ) )
Alternatively you could retract something from working memory that your rule relies on to be present or a match. For example, if you don't need it for anything later on, you could retract the attack vector:
retract( $av )
Yet another option might be to try and update your getThreatList() implementation to return a Set instead so you don't have duplicates (assuming threats are considered duplicates based on the 'impact' field.) Or you could try to remove all Application.Threats instances that match the criteria from the threatlist being returned.
We simply don't know enough about your use case or rule set to know what data you need or what it looks like, but at the end of the day you simply need the rule to fire once and only once, so to do this you need to somehow update the rule to know that it's no longer valid.

Drools trigger one rule per item in list input for StatelessKieSession

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,

Drools Check for Non-Existence isnt behaving like id expect

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.

Drools if and else based on condition from another rule

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,

Why doesn't rule 1 consequence effect behavior of rule 2?

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.