Drools: using rule "exists" for a Map(Scala) - scala

I have a class "Records" which has a Map[String,Double](Scala) attribute "payOrders" and I want to find out whether the map contains value larger than 50. The rule I wrote is like this:
rule "user1"
dialect "mvel"
no-loop
when
$user:Records($pay:payOrders.values)
exists(Number(doubleValue > 50) from $pay)
then
System.out.println("user1")
end
The problem is there is no error but the rule doesn't work! No outputs.
Then, I tried to print $pay. The output is $pay:MapLike(300.0). First I thought drools can't analyze this type, so I revised $user:Records($pay:payOrders.values) to $user:Records($pay:payOrders.values.toList). But it still prints nothing. It seems that once I added the exists line, the rule just don't work.
Can anyone help me? Thanks!

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.

how to know the rules which are using a particular attribute

Say I have a rule file like below. Below rules are built on 2 properties Instrument and maverickModelMappingId. Can Drools tell me how many rules use the field "Instrument"? My use case is that I want to know if I am deleting an attribute or a field, how many rules and which rules are going to be affected.
package abc.modelMapping.ruleEngine;
dialect "java"
declare FRONTOFFICESYSTEM
Instrument : String
maverickModelMappingId : String
end
rule "rule_MurexCredit_Rule_3"
salience 3
no-loop true
when
$frontOfficeSystem : FRONTOFFICESYSTEM("Default swap".equalsIgnoreCase(Instrument))
then
$frontOfficeSystem.setMaverickModelMappingId("001282");
System.out.println("001282 "+"MurexCredit_Rule_3+");
end
rule "rule_MurexCredit_Rule_2"
salience 2
no-loop true
when
$frontOfficeSystem : FRONTOFFICESYSTEM("Euro credit index option".equalsIgnoreCase(Instrument))
then
$frontOfficeSystem.setMaverickModelMappingId("001283");
System.out.println("001283 "+"MurexCredit_Rule_2+");
end
rule "rule_MurexCredit_Rule_1"
salience 1
no-loop true
when
$frontOfficeSystem : FRONTOFFICESYSTEM("Credit index".equalsIgnoreCase(Instrument))
then
$frontOfficeSystem.setMaverickModelMappingId("001282");
System.out.println("001282 "+"MurexCredit_Rule_1+");
end
This is not possible with Drools, as of the current version (7.33.0.Final). As mentioned in the comments, the better solution will be to use your IDE's search tools -- or other find/grep solution -- to search the text of the rule file(s) for references to the given attribute or method.

Drools always return null

I have a .drl file generated from a rule xls:
#From row number: 19
rule "check_19"
salience 65517
activation-group "testCheck"
when
application : Application(eval( isApplicantType(applicantType, "SINGLE")))
applicant : Applicant(eval(isValid("18")))
then
result.add("false");
end
The drools fires without any errors but the result is always null. The activation group testCheck is set to XOR so I'm assuming either one of application or applicant must be true. Can someone explain to me the issue here? Thanks

drools rule for fact with list values and multiple conditions

i am attempting to write a rule that will compare a fact list values to a multiple condition rule
rule: only valid legislations
when
fact:Fact (legislationList == ('L1' && 'L2') OR 'L3')
then
fact.printMessage();
end
ie. if fact.legislationList={'L1', 'L2') then fire
if fact.legislationList={'L1', 'L4') then dont fire
i looked at the 'from' clause but wasnt clear how that would solve my issue.
is there some voodoo method/solution that will help me?
thanks
-lp
Assuming that legislationList is a List<String>, then you could use Drools' 'contains' operator:
rule: only valid legislations
when
fact:Fact ((legislationList contains "L1" && legislationList contains "L2") || legislationList contains "L3" )
then
fact.printMessage();
end
You can abbreviate the syntax a bit, but I wanted to be explicit.
Hope it helps,

Drools rule "not exists"

I'm using JBoss Drools to write some business rules. I got a problem on the "not exists" rule.Here is my code.
rule "ATL 27R-A12 Subfleet A319-100 Departure configuration list has flap 1"
salience 20
no-loop true
when
AircraftConfig(aircraftType=="A319-100")
RunwayInfo(airport3lCode== "ATL", runwayId == "27R-A12" )
not (exists (DepartureConfiguration( flap == 1 )))
then
throw new RuleNotMatchException("The configurations do not match the rule of this runway.");
end
My facts contains:An AircraftConfig, an RunwayInfo and several DepartureConfigurations. I want to fire the rule when there are no DepartureConfiguration which flap=1. I mean, if there are three DepartureConfigurations, one of them has the flap=1, the others are flap=2 or flap=3, then this rule will not fire.
How could I make this work?
The keyword for checking for the non-existence of a fact is not, not not exists. Change the last line of your condition to:
not DepartureConfiguration( flap == 1 )
Actually, I made some conflict in my rules. I used to think the rules should be ran from the top to the end of the drl file. I solved my problem by adding a rule flow. Also thanks to you guys who give me suggestions.