You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Drools 8.29.0中DRL文件的集合匹配与MVEL自定义比较实现

Drools 8.29.0中MVEL集合操作问题解决方案

问题背景

使用Drools 8.29.0时,DRL规则里的基础匹配规则(如匹配name为"abc")能正常触发,但两个集合匹配规则(M1、M2)完全无效。当前有两个核心需求:

  1. 优化多对多集合匹配的实现方式,现有写法Test( contactNumbers contains "1234" && contactNumbers contains "5678" )过于繁琐,寻求更简洁高效的方案;
  2. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 11:40:32