Facts can be selected in rank order with a defquery and a Java collection.

(deftemplate sample
    "Sample facts to be ranked"
    (declare (ordered FALSE))
    (slot primary (type INTEGER) (default 0))
    (slot secondary (type INTEGER))
    (slot stuff)
)

(defquery sample-query
    "Query for well-formed samples with an exclusion"
    (declare (variables ?exclude))
    ?sample <- (sample (primary ?primary&~nil)
                       (secondary ?secondary&~nil)
                       (stuff ~?exclude)))

(deffunction top-samples (?threshold ?criterion)
    "Print top N sample facts according to criterion"
    (bind ?tree-set (new java.util.TreeSet ?criterion))
    (bind ?samples (run-query* sample-query nil))
    (while (?samples next)
        (call ?tree-set add (?samples get sample)))
    (close ?samples)
    (bind ?iterator (?tree-set iterator))
    (while (and (?iterator hasNext) (> ?threshold 0))
        (-- ?threshold)
        (bind ?sample (?iterator next))
        (printout t "Sample fact: "
                  (fact-slot-value ?sample primary) " "
                  (fact-slot-value ?sample secondary) " "
                  (fact-slot-value ?sample stuff) crlf)))

(defglobal ?*compare-samples* =
    (implement java.util.Comparator using
               (lambda (?dummy ?first ?second)
                   (bind ?name1 (fact-slot-value ?first primary))
                   (bind ?name2 (fact-slot-value ?second primary))
                   (if (< ?name1 ?name2) then
                       (return -1))
                   (if (> ?name1 ?name2) then
                       (return 1))
                   (bind ?name1 (fact-slot-value ?first secondary))
                   (bind ?name2 (fact-slot-value ?second secondary))
                   (if (< ?name1 ?name2) then
                       (return -1))
                   (if (> ?name1 ?name2) then
                       (return 1))
                   0)))

(deffacts sample-facts
    "Sample fact examples to be ranked"
    (sample (primary 1) (secondary 10) (stuff "A"))
    (sample (primary 1) (secondary 11) (stuff "B"))
    (sample (primary 2) (secondary 5) (stuff "C"))
    (sample (primary 2) (secondary 6) (stuff "D"))
    (sample (primary 2) (secondary 6) (stuff "E"))
    (sample (primary 2) (secondary 7) (stuff "F"))
    (sample (primary 3) (secondary 9) (stuff "G"))
    (sample (primary 3) (stuff "H"))
    (sample (primary 1) (stuff "I"))
)

Jess> (reset)
TRUE
Jess> (top-samples 3 ?*compare-samples*)
Sample fact: 1 10 A
Sample fact: 1 11 B
Sample fact: 2 5 C
FALSE

Many variations are possible.
- To avoid recalculating an expensive comparison function, the criteria could 
be pre-calculated as the key of a TreeMap instead of a TreeSet.
- The java.util.Collections.sort method could sort any java.util.List 
collection instead of a TreeSet.
- A rule could add items to a collection instead of a defquery.

Bob Kirby

At 04:43 AM 11/27/2007, Jan Willem Lokin wrote:
>Hi,
>
>Consider the following situation. I have asserted quite a number of
>facts, with various values for their slots. Now I want to select a
>limited number of facts that are most suitable, according to some
>user-defined criterion.
>
>My idea was to set up a defquery and then use Java sorting to order
>the QuertResult according to my criterion. However, there seems to be
>no way to transform a QueyResult into a Collection.
>
>Note that my problems would be simple if I had fixed limits on my slot
>values, but I haven't: if i woudl have slot values of 2, 4 and 6 and I
>would like to have the smallest two, a limit of 5 would do it, but
>this would not work when the values were 13, 15 and 29.
>
>My suspicion is that I am trying to solve the problem in the wrong
>manner, or even trying to solve the wrong problem. Any suggestions are
>appreciated.
>
>Regards,
>
>JW Lokin

Reply via email to