Drools 8.29.0中DRL文件的集合匹配与MVEL自定义比较实现
Drools 8.29.0中MVEL集合操作问题解决方案
问题背景
使用Drools 8.29.0时,DRL规则里的基础匹配规则(如匹配name为"abc")能正常触发,但两个集合匹配规则(M1、M2)完全无效。当前有两个核心需求:
- 优化多对多集合匹配的实现方式,现有写法
Test( contactNumbers contains "1234" && contactNumbers contains "5678" )过于繁琐,寻求更简洁高效的方案; - 在MVEL中实现自定义集合过滤逻辑,比如判断事实集合与规则指定列表是否存在至少2项匹配,需要可参考的示例。
现有代码
Test Fact类
package com.abc; @Data @AllArgsConstructor public class Test { private String name; private List<String> contactNumbers; }
DRL规则文件
import com.abc.Test; rule "name-rule" when t : Test( name == "abc" ); then System.out.print("abc found"); end; // 无法生效的规则 rule "M1 rule-data matches fact" when p : Test( ["1234", "5678"] contains contactNumbers ); then System.out.print("M1 rule-data matches fact FOUND"); end; // 无法生效的规则 rule "M2 fact matches rule-data" when p : Test( contactNumbers contains ["1234", "5678"] ); then System.out.print("M2 fact matches rule-data FOUND"); end;
测试主代码片段
// 创建Fact对象 String[] s1 = {"1234", "5678", "2222"}; Test t1 = new Test("abc", Arrays.asList("1111")); Test t2 = new Test("xyz", Arrays.asList(s1)); // 插入事实并触发规则 KieSession kieSession = kieContainer.newKieSession(); kieSession.insert(t1); kieSession.insert(t2); kieSession.fireAllRules(); kieSession.dispose();
解决方案
1. 多对多集合匹配的优化实现
原M1、M2规则失效的原因是:MVEL的contains运算符仅支持单个元素与集合的包含判断,不能直接用于集合与集合的匹配。以下是几种更优方案:
方案1:使用MVEL Lambda简化全匹配
如果需要判断规则指定的所有元素都存在于事实集合中,可以用MVEL的all运算符实现简洁写法:
rule "全元素匹配" when p : Test( ["1234", "5678"].all( num -> contactNumbers.contains(num) ) ) then System.out.println("事实集合包含所有指定号码"); end;
方案2:基于集合交集的灵活匹配
如果需要判断事实集合与规则列表的交集大小满足条件(比如至少2个匹配),可以利用retainAll获取交集后判断长度:
rule "交集大小匹配" when p : Test( (contactNumbers.retainAll(["1234", "5678", "9012"])).size() >= 2 ) then System.out.println("事实集合与规则列表匹配至少2项"); end;
方案3:Drools内置collect/from实现复杂匹配
对于更复杂的集合匹配场景,结合from和collect可以清晰实现逻辑:
rule "collect实现多元素匹配" when $test: Test() // 收集事实集合中属于规则列表的元素,判断数量>=2 $matchedNums: List(size >= 2) from collect( String() from $test.contactNumbers this in ["1234", "5678", "9012"] ) then System.out.println("匹配到的号码:" + $matchedNums); end;
2. MVEL中实现自定义比较逻辑
可以通过两种方式实现自定义集合过滤需求:
方式1:直接在MVEL中编写Lambda/Stream逻辑
无需额外工具类,直接在eval或属性判断中编写Java Stream逻辑:
rule "Lambda自定义匹配" when $test: Test() eval( $test.getContactNumbers().stream() .filter(num -> Arrays.asList("1234", "5678", "9012").contains(num)) .count() >= 2 ) then System.out.println("自定义匹配规则触发:至少2项匹配"); end;
方式2:封装Java工具类复用逻辑
如果自定义逻辑需要在多个规则中复用,建议封装成工具类:
package com.abc.utils; import java.util.List; public class CollectionMatcher { // 自定义方法:判断事实集合与目标列表的匹配数是否达到阈值 public static boolean hasEnoughMatches(List<String> factList, List<String> targetList, int minMatches) { long matchCount = factList.stream() .filter(targetList::contains) .count(); return matchCount >= minMatches; } }
在DRL中导入并调用:
import com.abc.Test; import com.abc.utils.CollectionMatcher; import java.util.Arrays; rule "工具类自定义匹配" when $test: Test( CollectionMatcher.hasEnoughMatches( contactNumbers, Arrays.asList("1234", "5678", "9012"), 2 ) ) then System.out.println("工具类实现的自定义匹配触发"); end;
内容的提问来源于stack exchange,提问作者axnet
相关产品推荐
相关产品推荐

