Search code examples
javarule-enginemvel

Easy-Rules Rule engine, cannot fire on multiple facts at once


I am trying to extend the Shop Tutorial for easy rules (shop) to run on multiple facts. While writing the conditions in the rule we call functions using the "fact name" as below,

condition: "people.isAdult() == false"

Since, people is just the name of ONE object instance in facts, defining the condition like in above is no good. How can I define the condition such that it will iterate over multiple facts.

What I want to achieve is evaluate the rules on multiple facts in one fire of the rule engine.

When an array of facts with same fact name is supplied to the rule engine, only the last one supplied is evaluated. However, when different names are assigned to each fact, I cannot assign the same condition to each one.

Below you can see the code. Assume Person class have basic get/set functions for all members.

Rules.yml:

---
name: "regex"
description: "Check if regex pattern matches"
priority: 1
condition: "people.getPayload().matches(\".*12.*34$\") == true"
actions:
 - "System.out.println(\"There is a match\");"
---
name: "age"
description: "Check if person's age is > 18 and marks the person as adult"
priority: 2
condition: "people.age > 18"
actions:
  - "people.setAdult(true);"
---
name: "alkol"
description: "children are not allowed to buy alcohol"
priority: 3
condition: "people.isAdult() == false"
actions:
  - "System.out.println(\"Shop: Sorry, you are not allowed to buy portakal\");"

Main:

//create a person instance (fact)   
            Person [] PeopleArray = new Person [100];
            Person [] KidsArray = new Person [300];

        // initialize arrays
            for(int i = 0; i < PeopleArray.length ; i++)
            {
               PeopleArray[i] = new Person("TOM"+i,23);
               PeopleArray[i].setPayload(dummystring);
            }
            for(int i = 0; i < KidsArray.length ; i++)
            {
                KidsArray[i] = new Person("EMRE"+i,13);
                KidsArray[i].setPayload(dummystring);
            }


        Facts facts = new Facts();

        // create a rule set
        Rules rules = MVELRuleFactory.createRulesFrom(new FileReader("rules.yml"));

        RulesEngine rulesEngine = new DefaultRulesEngine();

        System.out.println("Tom: Hi! can I have some Vodka please?");

      //put the facts
        for(int i = 0; i < PeopleArray.length ; i++)
            facts.put("people", PeopleArray[i]);
        long start = System.currentTimeMillis();
        for(int i = 0; i < KidsArray.length ; i++)
            facts.put("people", KidsArray[i]);

        rulesEngine.fire(rules, facts);

Solution

  • A Facts object is essentially a hashmap. So by design, you cannot put two facts with the same key.

    I see in your example that the people fact is an array. Now how to handle arrays in a mvel expression is another story. To be honest, the best answer I can give is to look at the MVEL docs: https://github.com/imona/tutorial/wiki/MVEL-Guide#arrays

    What I want to achieve is evaluate the rules on multiple facts in one fire of the rule engine.

    I'm not sure this is possible with easy rules. I think you can:

    • Either flat map your facts
    • Or call fire multiple times on different facts

    Hope this helps.