Jess Information

Jess Home
Jess 7 Features
Download Now!
Online Demo

Documentation
FAQ
Manual
Mailing List
Jess Wiki

More information Related Web Sites
User Contributions
JSR94 Info
Developer's Log
About This Site

JESS ®, the Rule Engine for the JavaTM Platform

Jess Wiki: Valid Uses Of Test

The "test" conditional element allows you to use a predicate function as a constraint on the LHS of a rule. It is evaluated immediately after the preceding pattern (fact) is matched. Generally, however, itís considered a bad practice to use the test CE routinely in your rules. Instead, you should usually use connective constraints to constrain the fact being matched. Your rules should look like this:
    (defrule find-trustworthy-people
        (person (age ?X&:(< ?X 30))
        =>
        (printout t ?X " is under 30!" crlf))
rather than this:
    (defrule find-trustworthy-people
        (person (age ?X))
        (test (< ?X 30))
        =>
        (printout t ?X " is under 30!" crlf))
True, both versions of this rule will run about as efficiently. The advantage you gain when using connective constraints, as in the first example, is that the value being tested, "?X", is very clearly an attribute of the "person" fact. When using the test CE, anything may be under test. Youíll have to look further into the predicate function to see what variables are being used and which facts bind them to know exactly which facts are being tested.

There are a few "valid" uses of the test CE:

  • In certain, rare cases, the constraints on the LHS of a rule may be more easily and simply expressed using a test CE.
  • Long or complex functions may be easier to read if written in a test CE.
  • Comparison of a fact address requires a test CE.

This last bullet item requires some explanation. Say we have to assign two people to a job. We want to write a rule like this:

    (defrule assign-qualified-people-to-a-job
        (job
            (name           ?JOB_NAME)
            (requirement    ?R))
        (person
            (qualifications $? ?R $?)
            (name           ?P1_NAME))
        (person
            (qualifications $? ?R $?)
            (name           ?P2_NAME))
        =>
        (printout t "Assign " ?P1_NAME " and " ?P2_NAME " to job " ?JOB_NAME crlf))
The problem with this rule is that it isnít making sure that the two people assigned to the job are not the same person. The same person fact may match both patterns. One way we can guarantee different people are assigned to the job is by making sure the addresses of the person facts are not the same:
    (defrule assign-qualified-people-to-a-job
        (job
            (name           ?JOB_NAME)
            (requirement    ?R))
        ?Person1 <- (person
            (qualifications $? ?R $?)
            (name           ?P1_NAME))
        ?Person2 <- (person
            (qualifications $? ?R $?)
            (name           ?P2_NAME))
        (test (neq ?Person1 ?Person2))
        =>
        (printout t "Assign " ?P1_NAME " and " ?P2_NAME " to job " ?JOB_NAME crlf))
However, this mechanism for making sure we get different facts is only recommended when they donít have unique identifiers. If we add an employee Id number to the person fact, we may prefer to write this rule using a "not" connective constraint:
    (defrule assign-qualified-people-to-a-job
        (job
            (name           ?JOB_NAME)
            (requirement    ?R))
        ?Person1 <- (person
            (qualifications $? ?R $?)
            (employeeId     ?P1_EMP_ID)
            (name           ?P1_NAME))
        ?Person2 <- (person 
            (qualifications $? ?R $?)
            (employeeId     ~?P1_EMP_ID)
            (name           ?P2_NAME))
        =>
        (printout t "Assign " ?P1_NAME " and " ?P2_NAME " to job " ?JOB_NAME crlf))

Submitted by:
GeorgeWilliamson
Union Pacific Railroad
gawillia@up.com



FrontPage, JavaPitfalls


Front Page | Sandbox | Recent Changes | Powered by Friki | Last Edited: 18 October 2006