Search code examples
droolsrule-engine

Duplicate pojo validation rule in drools


I am inserting let's say about 1000 pojos of type A in to the kiesession how can I add a rule in drools to do some task if duplicate pojos exists for A in the kiesession.

class A {
     private int someInt;
     private String someString;
}

function boolean checkDuplicate(List input) {
    int a = input.size();
    int b = ((List) input.stream().distinct().collect(Collectors.toList())).size();
    return a!=b;
}

dialect "java"
rule "ADuplicateRule"
   when
        $input : List( ) from collect(A())
        eval(checkDuplicate($input))
   then
        throw new Exception("A list has duplicate values");
end

The above approach is working but is there a better more simpler way to achieve this?

like to do validation on sum of a field of pojo in the kiesession we can just simply write this

$sumSomeInt: Integer(this > 90) from accumulate(A( $SomeInt: someInt ), sum($SomeInt))

is it possible to do something on the similar lines to check for duplicates?


Solution

  • You were pretty close:

    rule "Duplicates Found"
    when
      A( $i: someInt, $s: someString )
      List( size > 1 ) from collect( A( someInt == $i, someString == $s ) )
    then 
      // handle the duplicate case
    end
    

    Adjust your equality check as needed. I would recommend not throwing an exception out of the 'then'.

    Alternatively, you don't even need to collect a full list of duplicates; it's sufficient that there exists at least one duplicate. This makes your rule more like this:

    rule "Duplicates found - v2"
    when
      $a: A( $i: someInt, $s: someString )
      exists( A( this != $a, someInt == $i, someString == $s ))
    then
      // handle the duplicates case
    end
    

    In these rules we're taking advantage of the fact that Drools will implicitly check all instances of A in working memory. So in the first rule, for each A, it will check to see if there are duplicates of that instance; if there are, the rule triggers. Otherwise it checks the next instance of A, and so on, until all instances of A have been evaluated.

    The second rule relies on the same sort of workflow, but also includes a this != $a check on the exists clause to verify that the "duplicate" we found isn't actually the instance we're checking. Since the first rule only triggers for List( size > 1 ), it expects that the instance we're checking will be included in the result of the collect.