Drools / JBoss LHS rule writing problem where I match one fact and then using that fact to determine if another fact exists
I am using Drools (for the first time) to express some rules and it has been working very well so far. However, I have been given a new condition, which I cannot express in the language of rules very clearly.
Basically, I need to take an action on the players account if they have an outstanding account balance between a certain amount, where they didn't make a payment last week, and where they didn't make a payment in the last 4 weeks, which is greater than or equal to a weekly deduction. There are a few more rules, but I've removed them to simplify the rule for this question. This is the last rule that is causing me the 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 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, it just doesn't work, I keep getting org.drools.rule.InvalidRulePackage exceptions. I was just guessing about the syntax, but couldn't find an example that showed what I am trying to do. Is it possible?
Complete original error message:
"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"
source to share
yes, you guessed it, you need to add an explicit "and" inside the template "not" to combine them.
The only time you don't need "and" is at the top level:
eg
when Foo() Bar()
Not required "and"
but this is implicitly the same as
when Foo() and Bar()
So your solution seems to be correct. The lack of a top-level "and" seems to be a convention in most rule languages (fallback to CLIPS!)
source to share
After some hacks around the following, it doesn't throw runtime errors (although I'm not sure if it's "fixed" yet). I rewrote the proposal to put a creature around both facts and use infix and 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.
source to share