Drools rule multiple objects with multiple constraints - drools

I have following rule
rule "Row LoanApproval"
dialect "mvel"
when
f2 : Loan( amount >= 0 )
f1 : Applicant( creditScore <= 200 )
then
f2.setApproved( true );
System.out.println("rule call");
end
My problem is value of field "approved" will be true when amount>=0. Second constraint f1 : Applicant( creditScore <= 200 ) plays no role here.
so how can I write it when both conditions are true. then "approved" should be true?

Related

Make rule on drolls to check subdata

I have a package. Package includes a list of items. Item has a list of fields. I need to check if specific fields are set to correct value for all items in a package:
rule "Slapper"
dialect "mvel"
when
itm : item( ) from pkg.items
List( size() == itm.size() ) from collect (
field( fieldId == "111" , value == "1" ) from itm.fields
field( fieldId == "222" , value == "2" ) from itm.fields
) from itm
then
...
end
how I can get collection filtered by subfields?
Need to use accumulate function:
List( size == pkg.items.size() ) from accumulate (
$a: itemData( $field1: fields, $field2: fields ) from pkg.items
and
fieldData( fieldId == "111" , value == "1" ) from $field1
and
fieldData( fieldId == "222" , value == "2" ) from $field2;
collectList( $a )
)

I want to remove objects from working memory EXCEPT for one specific one

Using Drools 5.5.FINAL. I have a rule that detects when there is exactly one ACTIVE Contract record from among multiple Contract records in working memory.
/**
* There is exactly ONE Active Contract
*/
rule "Exactly one ACTIVE among multiple"
salience 870
activation-group "BRValidation"
no-loop
when
$bmsContract : BMSContract( STAT_CD == BMS_Contract_Status.ACTIVE.toString() )
not BMSContract( this != $bmsContract, STAT_CD == BMS_Contract_Status.ACTIVE.toString() )
$blueReport : BlueReport( status == null )
then
logger.info("Rule detected one ACTIVE record from among multiple contracts;" + " Rule=" + drools.getRule().getName());
modify ( $blueReport ) {
setStatus( BlueReportStatus.SUCCESSFUL.toString() ),
setReason( "Single ACTIVE status among many contracts - that's OK"),
appendRuleAudit(drools.getRule().getName());
}
end
What I need to do in the RHS is to remove all instances of BMSContract object except for the one that has "ACTIVE" STAT_CD. How can I do that?

Drools guided decision table: Find which specific condition in rule caused the rule failure.

I have used guided decision table from kie-workbench.
This is the rule I have written
rule "Row 1 Coupons"
dialect "mvel"
when
f1 : CartDetails( couponCode == "OS1000" , startDate after "12-Jan-2017" , expiryDate before "31-Jul-2017" , minPurchaseAmt >= 5000.0 , excludeProductCodes excludes "GC669010,GC669011,GC669012,GC669013,GC669014,GC669015,GC669016,GC669017,GC669018,GC669019,GC669001,GC669002,GC669003,GC669004,GC669005,GC669006,GC669007,GC669008,GC669009,AC669001,GC669047,GC669052,RN669001,ER855036" , newUser == true )
then
f1.setDiscountAmt( 1000.0 );
f1.setDiscountPercentage( 0.0 );end
In case of rule failure, I want to know which specific condition caused this rule to fail.

drools not exists in collection

I need to fire a rule if a collection does not have a specific object.
AuditAssignment is available as problem fact.
AuditAssignment has a property "requiredSkill"
Audit Assignment has a property "auditor"
Auditor object has a list of "qualifications" which is a collection of "requiredSkill "
Now , I need to check , if the qualifications of the auditor in the auditassignment object has the requiredSkill
Below is sample rule which I tried but does not work .
rule "checkIfAuditSkillIsMatching"
when
$auditAssignment : AuditAssignment( $neededSkill : requiredSkill.getSkillCode())
$auditor : Auditor( $auditorSkills : qualifications)
not exists ( Skill ( skillCode == $neededSkill ) from $auditorSkills )
then
System.out.println( " **** " + $neededSkill);
scoreHolder.addHardConstraintMatch(kcontext, -1 );
end
I have tried the below one as well
rule "checkIfAuditSkillIsMatching"
when
$validAuditorCount : Number ( intValue < 1 ) from accumulate (
$auditor : Auditor( $auditorSkills: qualifications )
and exists AuditAssignment( auditor == $auditor ,
$auditorSkills.contains(requiredSkill) ) ,
count($auditor)
)
then
scoreHolder.addHardConstraintMatch(kcontext, -1 );
end
Here it is advisable to use a property method of Collection to obtain the logical value you need.
rule "checkIfAuditSkillIsMatching"
when
$auditAssignment: AuditAssignment( $neededSkill: requiredSkill.getSkillCode() )
$auditor: Auditor( $auditorSkills: qualifications,
! $auditorSkills.contains( $neededSkill ) )
then
//...no suitably qualified auditor
end
The below configuration worked
rule "checkIfAuditSkillIsMatching"
when
$auditAssignment : AuditAssignment( $neededSkill : requiredSkill ,
$assignedAuditor : auditor )
$auditor : Auditor( this == $assignedAuditor , !qualifications.contains($neededSkill) )
then
scoreHolder.addHardConstraintMatch(kcontext, -1 );
end

Problem writing LHS of Drools / JBoss Rules where I'm matching one fact and then using that fact to determine whether another fact exists

I'm using Drools (for the first time) to express some rules and it has been working really well so far. However I've been given a new condition that I'm not able to express in the rules language very clearly.
Essentially I need to perform an action on the players account if they have an outstanding balance on there account between a certain amount, where they haven't made a payment in the last week and where they haven't made a payment in the last 4 weeks that is greater than or equal to a weekly deduction. There are a few other rules but I've removed them in an effort to simplify the rule for this question. It's the last rule that is causing me a problem.
rule "The broken rule"
salience 10
no-loop
when
Player( $playerNumber : playerNumber )
$a : Account( // balance between £5 and £100 and no arrangement
playerNumber == $playerNumber &&
accountBalanceInPence >= 500 &&
accountBalanceInPence <= 10000
)
not ( // no payment in last week
exists AccountTransaction(
playerNumber == $playerNumber &&
transactionDate >= oneWeekAgo &&
transactionCode == "P" // payment
)
)
/* It's this next bit that is broken */
not ( // no payment > (weekly cost * 4) paid within last 4 weeks
$deduction : AccountTransaction( // a recent transaction
playerNumber == $playerNumber &&
transactionDate >= fourWeeksAgo &&
transactionCode == "D" // deduction
)
exists AccountTransaction( // the payment
playerNumber == $playerNumber &&
transactionDate >= fourWeeksAgo &&
transactionCode == "P" // payment
amountInPence >= ($deduction->amountInPence * 4)
)
)
then
// do some action to the account
end
The problem is that it just doesn't work, I keep getting org.drools.rule.InvalidRulePackage exceptions thrown. I was just guessing on the syntax but couldn't seem to find an example that showed what I'm trying to do. Is it even possible?
The full original error message is:
"unknown:50:3 mismatched token: [#255,1690:1695='exists',<39>,50:3]; expecting type RIGHT_PAREN[54,4]: unknown:54:4 mismatched token: [#284,1840:1852='amountInPence',<7>,54:4]; expecting type RIGHT_PAREN[54,22]: unknown:54:22 Unexpected token '$payment'"
After trying the suggestion in the first comment the error is:
"[50,3]: unknown:50:3 mismatched token: [#255,1690:1695='exists',<39>,50:3]; expecting type RIGHT_PAREN[54,4]: unknown:54:4 mismatched token: [#284,1840:1852='amountInPence',<7>,54:4]; expecting type RIGHT_PAREN[54,45]: unknown:54:45 mismatched token: [#293,1881:1881='*',<71>,54:45]; expecting type LEFT_PAREN[55,3]: unknown:55:3 mismatched token: [#298,1890:1890=')',<12>,55:3]; expecting type THEN"
yes as you guessed, you need to put an explicit "and" inside the "not" pattern to join them together.
The only time you don't need the "and" is at the top level:
eg
when Foo() Bar()
Doesn't require a an "and"
but this is implicitly the same as
when Foo() and Bar()
So your solution seems correct. The lack of a top level "and" seems to be convention in most rule languages (going back to CLIPS !)
After some more hacking around the following doesn't cause any runtime errors (though I'm not sure if it's "correct" yet). I rewrote the clause to put the exists around both the facts and used an infix and to group them.
not ( // no payment > (weekly cost * 4) paid within last 4 weeks
exists (
AccountTransaction( // a recent transaction
playerNumber == $playerNumber &&
transactionDate >= fourWeeksAgo &&
transactionCode == "D" // deduction
$recentDeducation : amountInPence
) and
AccountTransaction( // the payment
playerNumber == $playerNumber &&
transactionDate >= fourWeeksAgo &&
transactionCode == "P" // payment
amountInPence >= ($recentDeducation * 4)
)
)
)
Thanks for all the help so far.
What about ($deduction->amountInPence * 4)? I think, the -> should be a . instead.