oracle-samples/clara-rules

Drools conversion

victorrodrigueznadq opened this issue · 9 comments

We're converting our drools rules to Clara rules and I'm having trouble figuring out how to convert this LHS (left hand side) syntax to a clara syntax:

BigDecimal(doubleValue>=325) from accumulate (NbboStatistics(ownerCrdNumber==$firmIdentifier,$avgNbbo10:avgNbbo10),sum($avgNbbo10))

Any suggestions? Would it be something like the following?

  [?sum <- (acc/sum :avgNbbo10) :from [NbboStatistics
    (= ownerCrdNumber ?firmIdentifier)
    (= ?avgNbbo10 avgNbbo10)
  ]]
  :test (>= (.doubleValue ?sum) 325)

Thanks in advance for your help and suggestions!

i might be making some assumptions here but i believe that:

[Firm (= ?firmIdentifier firmIdentifier)]
[?sum <- (acc/sum :avgNbbo10) :from [NbboStatistics
    (= ownerCrdNumber ?firmIdentifier)]]
:test (>= (.doubleValue ?sum) 325)

The assumption i added was that there was a prior condition providing the bound ?firmIdentifier variable.

I removed (= ?avgNbbo10 avgNbbo10) as this would have formed a new binding within the accumulator, leading to a "group-by" mechanic on the value of the field, which doesn't seem to match my perceived intent of the rule.

Let me know if the above is accurate and suits your needs.

BigDecimal(doubleValue>=325) from accumulate

@EthanEChristian correct, here's what I have so far....I've written a converted to help us convert our drools rules to clara, and as you can see, it doesn't yet know how to handle properly the syntax I pasted above. I guess the reason we bound that variable in drools was to use it in the sum function. I take it that should not be required with what you provided above?

(defrule assign-qmm-tier-1
  "Assign QMM Tier 1"
  {:salience 7500}
  [?calculatedRatio <- CalculatedRatio
    (= ?calculatedRatioCode calculatedRatioCode)
    (= ?firmIdentifier firmIdentifier)
    (= ?ratio ratio)
  ]
  [?tier <- Tier
    (= ?qmmTierCode tierCode)
    (= calculatedRatioCode ?calculatedRatioCode) 
    (= tierGroup "QmmTier1") 
    (= tierLevel Tier$TierLevel/COMMON_OWNERSHIP) 
    (= tierType Tier$TierType/RATIO) 
    (and (<= (.compareTo min ?ratio) 0) (or (= max nil) (> (.compareTo max ?ratio) 0)))
  ]
  [BigDecimal
    (>= doubleValue 325) 
  ]
  =>
;; Status status = new Status($calculatedRatio,$tier,StatusLevel.COMMON_OWNERSHIP);
;; $statusWriter.writeData(status);
;; insert(status);
  (def status (Status. ^CalculatedRatio ?calculatedRatio ?tier Status$StatusLevel/COMMON_OWNERSHIP))
  (insert! (Map/of "$statusWriter" status))
  (insert! status)
)

Correct @victorrodrigueznadq, the binding would be unneeded as the accumulator def for sum:
https://github.com/cerner/clara-rules/blob/327eef5e3abc4f42e6732a5548821f0d36d62cdb/src/main/clojure/clara/rules/accumulators.cljc#L157-L158
uses the provided accessor directly while applying the summation.

I might also suggest for the RHS to generate a let block instead of a def if possible, something like:

(let [status (Status. ^CalculatedRatio ?calculatedRatio ?tier Status$StatusLevel/COMMON_OWNERSHIP)]
  (insert! (Map/of "$statusWriter" status)) 
  (insert! status))

Correct @victorrodrigueznadq, the binding would be unneeded as the accumulator def for sum:

https://github.com/cerner/clara-rules/blob/327eef5e3abc4f42e6732a5548821f0d36d62cdb/src/main/clojure/clara/rules/accumulators.cljc#L157-L158

uses the provided accessor directly while applying the summation.
I might also suggest for the RHS to generate a let block instead of a def if possible, something like:

(let [status (Status. ^CalculatedRatio ?calculatedRatio ?tier Status$StatusLevel/COMMON_OWNERSHIP)]
  (insert! (Map/of "$statusWriter" status)) 
  (insert! status))

Yeah @EthanEChristian I'm working on that. baby steps....... learning clojure and trying to convert java to clojure programatically is tough! hehehe. Thanks! May I ask why let is preferred to def?

def would create a global var in the namespace that the rule was defined, meaning that each time the RHS was executed it would be doing a form of stateful manipulation.

I would wager that it would likely go unnoticed, unless you were running multiple sessions at the same time perhaps a multi threaded application of sorts. In which case, the global vars could theoretically be mutated by other sessions and alter the results across sessions.

let in this case would be favorable as it would scope the bindings down to just the RHS, or rather the function that is used to execute the RHS during rules execution.

@EthanEChristian ok, I've got it. the only thing is that I had to surround the :test in brackets to get it to compile. Looks good? (this is another example)

  [?averageRatio <- (acc/average :ratio) :from [CalculatedRatio
    (= accountIdentifier ?accountId) 
    (= calculatedRatioCode "nqeAddDlpRatio") 
    (= calculatedRatioLevel CalculatedRatio$CalculatedRatioLevel/ACCOUNT) 
  ]]
  [:test (>= (.doubleValue ?averageRatio) .05) ]

ope you are correct, i was focusing on everything but the test condition.
I do believe that the LHS above looks as expected.

@victorrodrigueznadq were there any outstanding questions that i could answer?

@EthanEChristian no, thanks. Closing.