Reputation: 5780
Note: drools version used is 8.29.0
I want to perform a set based operations in drl file using mvel.
for e.g. drl file for simple rule match
// Test Fact Class
package com.abc;
@Data
@AllArgsConstructor
public class Test {
private String name;
private List<String> contactNumbers;
}
// drl rules file
import com.abc.Test;
rule "name-rule"
when
t : Test( name == "abc" );
then
System.out.print("abc found");
end;
// not working
rule "M1 rule-data matches fact"
when
p : Test( ["1234", "5678"] contains contactNumbers );
then
System.out.print("M1 rule-data matches fact FOUND");
end;
// not working
rule "M2 fact matches rule-data"
when
p : Test( contactNumbers contains ["1234", "5678"] );
then
System.out.print("M2 fact matches rule-data FOUND");
end;
// main method snippet
// creating Fact objects
String[] s1 = {"1234", "5678", "2222"};
Test t1 = new Test("abc", Arrays.asList("1111"));
Test t2 = new Test("xyz", Arrays.asList(s1));
// inserting facts to check against rules
// kieContainer is created using above mentioned drl file
KieSession kieSession = kieContainer.newKieSession();
kieSession.insert(t1);
kieSession.insert(t2);
kieSession.fireAllRules();
kieSession.dispose();
When I execute above, I only get to match rule 1, which outputs "abc found".
Question:
How can I achieve many to many match in drl file.
Ans : one way i figured is below.
Test( contactNumbers contains "1234" && contactNumbers contains "5678" );
if any other better way than above, please let me know.
How can I achieve or implement the custom comparisons in MVEL?
i.e. If any 2 items of the facts matches the list present in rule etc., or any custom filtering on collections.
any example of such implementation would be really useful.
Upvotes: 0
Views: 327
Reputation: 15184
contains
and memberOf
are for a single value and a list. Which you use depends on which you have in the object in working memory, and which you're defining in the rule.
Examples:
"contains":
ClassMates( names contains "Jim" )
"memberOf":
Person( $name: name )
Classmates( $name memberOf names )
So for your example, you'd likely do:
Test(contactNumbers contains "12345",
contactNumbers contains "67890" )
This would trigger if the Test instance has a contactNumbers field that includes "12345" and "67890". contactNumbers could contain other values as well. If there are two Test instances, and one contains "12345" and the other contains "67890", this rule will not fire.
You can test that contactNumbers contains only the values you're testing for using an accumulate
and a length check:
$t: Test( $numbers: contactNumbers )
Set( size == $numbers.size() ) from accumulate(
$n: String(this in ("12345", "67890")) from $numbers,
collectSet($n)
)
I used a Set
to exclude duplicates. Older Drools you can do a similar with 'collect'.
I've matched your syntax here using Test(...)
. Note that the current docs recommend the "oopath" style of /tests [contactNumbers contains "12345", contactNumbers contains "6789"]
... other than the harder-to-read syntax it should be functionally the same.
Upvotes: 1