Problema nella scrittura di LHS delle regole Drools / JBoss in cui sto abbinando un fatto e quindi usando quel fatto per determinare se esiste un altro fatto
-
03-07-2019 - |
Domanda
Sto usando Drools (per la prima volta) per esprimere alcune regole e finora ha funzionato molto bene. Tuttavia mi è stata data una nuova condizione che non sono in grado di esprimere molto chiaramente nel linguaggio delle regole.
In sostanza, devo eseguire un'azione sul conto dei giocatori se hanno un saldo in sospeso sul conto tra un certo importo, in cui non hanno effettuato un pagamento nell'ultima settimana e in cui non hanno effettuato un pagamento in le ultime 4 settimane che sono maggiori o uguali a una detrazione settimanale. Ci sono alcune altre regole ma le ho rimosse nel tentativo di semplificare la regola per questa domanda. È l'ultima regola che mi sta causando un 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
Il problema è che semplicemente non funziona, continuo a ricevere eccezioni org.drools.rule.InvalidRulePackage. Stavo solo indovinando la sintassi ma non riuscivo a trovare un esempio che mostrasse quello che sto cercando di fare. È anche possibile?
Il messaggio di errore originale 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'"
Dopo aver provato il suggerimento nel primo commento, l'errore è:
"[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"
Soluzione
sì, come hai indovinato, devi inserire un esplicito " e " all'interno del "non" modello per unirli insieme.
L'unica volta in cui non hai bisogno di " e " è al livello più alto:
ad esempio
when Foo() Bar()
Non richiede un " e "
ma implicitamente è lo stesso di
when Foo() and Bar()
Quindi la tua soluzione sembra corretta. La mancanza di un livello superiore "e"; sembra essere una convenzione nella maggior parte delle lingue delle regole (tornando a CLIPS!)
Altri suggerimenti
Dopo qualche altro hacking in giro, ciò che segue non causa errori di runtime (anche se non sono ancora sicuro che sia "corretto"). Ho riscritto la clausola per mettere gli esistenti attorno a entrambi i fatti e ho usato un'infisso e raggrupparli.
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)
)
)
)
Grazie per tutto l'aiuto finora.
Che dire di ($ deduction- > amountInPence * 4)
? Penso che il - >
dovrebbe essere invece un .