Problema escrevendo LHS de Drools Rules / JBoss onde estou combinando um fato e, em seguida, usando esse fato para determinar se outro fato existe

StackOverflow https://stackoverflow.com/questions/415907

  •  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"
Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top