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

为何Drools规则引擎仅执行一次空条件规则?

Drools有状态Session中规则仅首次触发的问题

我搭建了一个基础的Drools规则引擎,仅配置了一条规则:

rule "Hello World"
    when
        
    then
        System.out.println("Hello World!");
end

我在Java线程的循环中运行该应用,每次循环都会调用有状态Kie Session的fireAllRules()方法触发规则。第一次循环成功打印了"Hello World!",但后续循环中该规则不再触发。

相关代码

run方法:

@Override
public void run() {   
   // Fire the rules
   System.out.println("Firing rules");
   kSession.fireAllRules();           
}

Kie Session初始化代码:

KieServices ks = KieServices.Factory.get();
KieContainer kContainer = ks.getKieClasspathContainer();
KieBase kBase1 = kContainer.getKieBase("KBase1");          
kSession = kBase1.newKieSession();

环境信息

  • Maven依赖:
    • drools-engine(版本9.44.0-Final)
    • drools-xml-support(版本9.44.0-Final)
    • drools-mvel(版本9.44.0-Final)
  • 使用插件:
    • kie-maven-plugin(版本9.44.0-Final)

我猜测这和引擎的推理机制有关,但对其原理理解不足,恳请解答!


问题原因与解决方案

核心原因

Drools的**有状态Session(Stateful Kie Session)**会维护规则的激活状态(Agenda)和工作内存(Working Memory)。对于没有when条件的规则(即永远满足触发条件的规则),首次调用fireAllRules()时,规则会被执行,Drools会标记该规则已被激活过——默认情况下不会重复触发,这是为了避免规则无限循环执行的设计。

解决方案

根据场景需求,可选择以下三种方式解决:

1. 使用无状态Session(Stateless Kie Session)

如果不需要维护工作内存状态,每次触发规则都要从头执行,改用无状态Session即可:

// 初始化无状态Session
StatelessKieSession kSession = kBase1.newStatelessKieSession();

// 触发规则
@Override
public void run() {   
   System.out.println("Firing rules");
   kSession.execute(new Object()); // 无状态Session需传入任意对象(即使未使用)
}

无状态Session每次执行都会重新初始化工作内存和Agenda,因此每次调用都会触发规则。

2. 重置Session的激活状态

若必须使用有状态Session,可在每次fireAllRules()后重置Agenda,清除已激活的规则记录:

@Override
public void run() {   
   System.out.println("Firing rules");
   kSession.fireAllRules();
   // 重置Agenda,让规则重新变为可激活状态
   kSession.getAgenda().clear();
}

下次调用fireAllRules()时,规则会被重新评估并触发。

3. 给规则添加可变化的触发条件

如果希望规则能根据状态变化重复触发,可给规则添加when条件,比如引入计数对象控制触发逻辑:
首先定义计数器类:

public class Counter {
    private int count;
    // 省略getter、setter方法
}

修改规则:

rule "Hello World"
    when
        $counter : Counter() // 匹配工作内存中的Counter对象
    then
        System.out.println("Hello World!");
        // 更新计数器状态,确保规则可重复匹配
        modify($counter) { setCount($counter.getCount() + 1) };
end

初始化Session时将Counter对象插入工作内存:

// Session初始化完成后执行
Counter counter = new Counter();
kSession.insert(counter);

这种方式下,每次fireAllRules()都会检查when条件是否满足,只要工作内存中存在对应对象(或状态更新),规则就会触发。

内容的提问来源于stack exchange,提问作者tarcin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 21:06:17