Problema escrevendo LHS de Drools Rules / JBoss onde estou combinando um fato e, em seguida, usando esse fato para determinar se outro fato existe
-
03-07-2019 - |
Pergunta
Eu estou usando Drools (pela primeira vez) para expressar algumas regras e que tem vindo a trabalhar muito bem até agora. No entanto eu tenho dado uma nova condição que eu não sou capaz de expressar no idioma regras de forma muito clara.
Essencialmente eu preciso executar uma ação em conta dos jogadores, se eles têm um saldo lá conta entre um determinado valor, onde não fez um pagamento na semana passada e onde não fez um pagamento em Nas últimas 4 semanas, que é maior ou igual a uma dedução semanal. Existem algumas outras regras, mas eu removi-los em um esforço para simplificar a regra para esta pergunta. É a última regra que está me causando um problema.
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
O problema é que ele simplesmente não funciona, eu continuo recebendo exceções org.drools.rule.InvalidRulePackage jogados. Eu estava apenas adivinhando sobre a sintaxe, mas não conseguia encontrar um exemplo que mostrou o que eu estou tentando fazer. Será que é mesmo possível?
A mensagem de erro original completo é:
"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'"
Depois de tentar a sugestão em primeiro comentário o erro é:
"[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"
Solução
Sim, como você adivinhou, você precisa colocar um explícito "e" dentro do "não" padrão para juntá-las.
A única vez que você não precisa do "e" está no nível superior:
ex
when Foo() Bar()
Não necessita de um "e"
mas isso é implicitamente o mesmo que
when Foo() and Bar()
Assim, sua solução parece correto. A falta de um nível superior "e" parece ser convenção na maioria das linguagens de regra (de volta ao CLIPS indo!)
Outras dicas
Depois de um pouco mais de hackers em todo o seguinte não causa quaisquer erros de execução (embora eu não tenho certeza se é "correta" ainda). Eu reescrevi a cláusula de colocar o existe em torno de ambos os fatos e usado um infixo e agrupá-los.
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)
)
)
)
Obrigado por toda a ajuda até agora.
E sobre ($deduction->amountInPence * 4)
? Eu acho que, a ->
deve ser um .
vez.