Search code examples
javajbossdroolskie

Multiple checks end in re-evaluation of rules in Drools Execution KIE


I have a set of rules which behave differently based on number of Objects they are evaluated against

I expect 2 rule to be executed for each Product class object passed.

  1. When I pass single object of Product 2 rules are executed( which is fine)

    Product product5= new Product();
        product5.setType("gold");
        product5.setBuyer("platinum");
        product5.setEvent("sale");
        product5.setName("product5");              
        ksession.insert(product5);
    
  2. When I pass two objects of the Product class the number of rules which get executed is 6 (which I fail to understand).

    Product product5= new Product();
    Product product3= new Product();
    //setting all fields in both objects
    ksession.insert(product5);
    ksession.insert(product3);
    

    I tried to debug this by adding Console prints, Here are my results

    Offer for Gold executed once for each object (expected).

    Offer for Gold on Festival executed twice for each object(should be two).

    Offer for Diamond was not invoked (expected)

  3. When I pass three objects of the Product class the number of rules which get executed is 12 (which I fail to understand). I tried to debug this by adding Console prints , Here are my results

    Offer for Gold executed once for each object (expected).

    Offer for Gold on Festival executed thrice for each object(should be two).

    Offer for Diamond was not invoked (expected)

Below is my DRL file

    rule "Offer for Diamond"
    when
    $productObject: Product(type == "diamond")
    then
    $productObject.setDiscount(15);
    end


    rule "Offer for Gold"
    salience 1

    when
    $productObject: Product(type == "gold")
    then
    $productObject.setDiscount(25);
    end


    rule "Offer for Gold on Festival"
    when
    $productObject: Product(type == "gold") && Product(event == "sale")
    then
    $productObject.setDiscount($productObject.getDiscount() + 5);
    end

Solution

  • Assuming your 2 objects have the same attributes, these are the rules (and facts) that get executed:

    • "Offer for Diamond": 0 times
    • "Offer for Gold": 2 times:
      • o1
      • o2
    • "Offer for Gold on Festival": 4 times
      • o1, o1
      • o1, o2
      • o2, o1
      • o2, o2

    As you can see, when you use && between patterns you are creating a cartesian product of all the possible combinations matching them.

    In "Offer for Gold on Festival", if you want the rule to be executed once for each object, then you must explicitly tell Drools that the 2 patterns are talking about the same object:

    rule "Offer for Gold on Festival"
    when
        $productObject: Product(type == "gold") && 
        Product(this == $productObject, event == "sale")
    then
        $productObject.setDiscount($productObject.getDiscount() + 5);
    end
    

    Now, if your rule is exactly like the one above, it can be simplified by simply doing:

    rule "Offer for Gold on Festival"
    when
        $productObject: Product(type == "gold", event == "sale")
    then
        $productObject.setDiscount($productObject.getDiscount() + 5);
    end
    

    In this case, because you don't have 2 patterns, the rule will be evaluated only once for each Product.

    Hope it helps,