Search code examples
drools

How to compare attribute of current row to attribute of previous row in Drools


Let's say I've got a simple pojo

    public class foo {
      private String id;
      private Date asOfDate;
      private String product;

      ...getters and setters...
}

I want to feed an bunch of foos into a rule, sort them based on the date, and then compare the current product to the previous product. Out of that compare, I want to create a new fact with an additional attribute called ProductChange. If the current product = the previous product, productChange will be set to "no change". If the current product <> the previous product, set it to "change".

Here's some sample sorted data:

| id |  asOfDate  | product |
+----+------------+---------+
|  1 | 2017-01-01 | A       |
|  1 | 2017-02-01 | A       |
|  1 | 2017-03-01 | B       |
|  1 | 2017-04-01 | C       |
+----+------------+---------+

And here's what the new facts would look like:

+----+------------+---------+---------------+
| id |  asOfDate  | product | productChange |
+----+------------+---------+---------------+
|  1 | 2017-01-01 | A       | No Change     |
|  1 | 2017-02-01 | A       | No change     |
|  1 | 2017-03-01 | B       | change        |
|  1 | 2017-04-01 | C       | change        |
+----+------------+---------+---------------+

Here's what I've got so far in the rule:

rule "compare"
    when 
      $foo : foo ($id : id, $asOfDate : asOfDate, $product : product)
      not foo (asOfDate < $asOfDate)
     then
        System.out.println("id: " + $id + " date: " + $asOfDate + "product: " + $product);
     end

This gets the set sorted correctly, but I have no idea how to approach looking at a previous row.


Solution

  • The easiest way is to create 2 rules: one for when 2 consecutives Foos have the same product and one for when the don't.

    rule "Same Product"
    when 
      $foo1 : foo ($id : id, $asOfDate1 : asOfDate, $product : product)
      $foo2 : foo (asOfDate > $asOfDate1, $asOfDate2:asOfDate, product == $product)
      not foo (asOfDate > $asOfDate, asOfDate < $asOfDate2)  //This will make sure that $foo1 and $foo2 are consecutive
    then
        $foo2.setProductChange("No change");
    end
    
    rule "Different Product"
    when 
      $foo1 : foo ($id : id, $asOfDate1 : asOfDate, $product : product)
      $foo2 : foo (asOfDate > $asOfDate1, $asOfDate2:asOfDate, product != $product)
      not foo (asOfDate > $asOfDate, asOfDate < $asOfDate2)  //This will make sure that $foo1 and $foo2 are consecutive
    then
        $foo2.setProductChange("change");
    end
    

    Be careful because these rules don't take into account different Foos with the same timestamp. You will need to tweek the < and > to make it work in this case.

    You will also need a separate rule for the first Foo, or you can add an OR in the first rule.

    Hope it helps,