Search code examples
rule-enginejessaccumulate

Jess defquery and accumulate CE


I am new to Jess The Rule Engine and I am having a trouble with a simple query. I have a simple java bean file and a .clp file . By using java bean file I create word objects and by using .clp I do some processes, by defining rules, on imported java objects which are now in the working memory of Jess. And at the end of the rules that I described I want to perform a query which will find the highest sentenceNumber - sentenceNumber is a slot variable in my Word fact- by using the accumulate conditional element. And also I want to return the resulting value to Java code. The problem is that the query that I wrote gives me error if I do use accumulate CE in the query but not in the defrule.

So my question is : Is it inappropriate to use accumulate CE in a query? I could not find any material which says yes or no.

Below I give you my query :

(defquery get-Total-Sentence-Number
 "this query gets the total number of newly created sentences"
 ;(accumulate <initializer> <action> <result> <conditional element>)
 ?result <- (accumulate (bind ?max FALSE) ;initializer
                        (if (or (not ?max);action
                        (> ?sentenceNumber ?max))
                             then (bind ?max ?sentenceNumber))
                        ?max ;result
                        (Word (sentenceNumber ?sentenceNumber))))

Please help. Thank you

p.s. I do not want to use the accumulate CE in a defrule because as I understood a rule will fire itself again and again in every change of the fact list. And I just want to perform this only once which I need it at the end of the rules that I defined.


Solution

  • I think there is a restriction. Anyway, it doesn't really make sense to run an accumulate in a query. It would be easier to define a query returning the facts:

    (defquery get-words
       (Word (sentenceNumber ?sentenceNumber)))
    

    to run it, and to evaluate the maximum in an iteration over the queried collection:

    (bind ?result (run-query* get-words))
    
    (bind ?max 0)
    (while (?result next) do
        (bind ?snr (?result getString sentenceNumber))
        (if (> ?snr ?max) then (bind ?max ?snr))
    )
    (printout t "max: " ?max crlf)
    

    Later Then I recommend the following approach:

    ;; define an auxiliary fact
    (deftemplate MaxWord (slot maxSentence))
    
    ;; initialze one fact
    (deffacts  maximum
      (MaxWord (maxSentence 0))
    )
    
    ;; a rule to compute the maximum
    (defrule setMax
      ?mw <- (MaxWord (maxSentence ?ms))
      (Word (sentenceNumber ?snr & :(> ?snr ?ms)))
    =>
      (modify ?mw (maxSentence ?snr))
    )
    
     ;; the query
    (defquery getMax
       (MaxWord (maxSentence ?maxSentence)))
    
    ;; obtain the result
    (bind ?result (run-query* getMax))
    (?result next)
    (bind ?max (?result getString maxSentence))
    (printout t "max: " ?max crlf)
    

    Note that this does not work correclty if Word facts are retracted, which is bound to invalidate the maximum.

    An entirely different approach can be made by using a rule with accumulate and an initial (auxiliary) fact that needs to be asserted when the rule should fire. This would avoid the frequent repetition of accumulate. Basically:

    (defrule "calcMax"
      (FreeToCalc)
      ?result <- (accumulate (bind ?max 0)
                        (if  (> ?sentenceNumber ?max)
                             then (bind ?max ?sentenceNumber))
                        ?max
                  (Word (sentenceNumber ?sentenceNumber))))
     =>
     ;;...
     )