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

如何在Drools规则中存储、传递各规则生成的中间计算值

Drools跨规则传递中间值解决方案

你的规则拆分思路完全符合Drools的最佳实践,将复杂计算拆分为多个独立的中间值规则,反而能大幅提升规则的可读性和可维护性,不存在思路问题。

Drools本身没有原生提供规则集内私有全局变量的能力,工业界通用的跨规则数据传递方案有以下两种:


方案1:自定义评分上下文Fact(最推荐)

这是最符合Drools设计范式的实现方式,完全满足你对「规则集内可用、可设置初始值」的需求:

  1. 先定义一个专门存储评分过程数据的上下文类,将中间值、最终得分都作为类属性,直接在类中配置默认初始值
  2. 触发规则前,将Person业务对象、上下文类对象同时插入Drools工作内存
  3. 所有中间值计算规则直接修改上下文对象的属性,最终得分规则直接读取上下文对象中已计算完成的中间值即可

代码示例

上下文类定义

import java.math.BigDecimal;
// 评分上下文Fact,仅在当前规则会话生命周期内有效
public class ScoreContext {
    // 直接设置初始值
    private BigDecimal intrmdt1 = BigDecimal.ZERO;
    private BigDecimal intrmdt2 = BigDecimal.ZERO;
    private BigDecimal intrmdt3 = BigDecimal.ZERO;
    private BigDecimal finalScore = BigDecimal.ZERO;

    // 省略所有属性的getter、setter方法
}

DRL规则示例

import com.yourpackage.Person
import com.yourpackage.ScoreContext
import java.math.BigDecimal

// 中间值1计算规则,优先级100(数值越大执行优先级越高)
rule "calcIntrmdt1"
salience 100
when
    $person: Person()
    $ctx: ScoreContext()
then
    // 此处编写你的中间值1计算逻辑
    BigDecimal calcResult = $person.getAge() == null ? BigDecimal.ZERO : BigDecimal.valueOf($person.getAge() * 2);
    $ctx.setIntrmdt1(calcResult);
    // 若有其他规则依赖该中间值触发,可加update($ctx)通知工作内存数据变更
end

// 中间值2计算规则,优先级99
rule "calcIntrmdt2"
salience 99
when
    $person: Person()
    $ctx: ScoreContext()
then
    // 中间值2计算逻辑
end

// 中间值3计算规则,优先级98
rule "calcIntrmdt3"
salience 98
when
    $person: Person()
    $ctx: ScoreContext()
then
    // 中间值3计算逻辑
end

// 最终得分计算规则,优先级最低,确保所有中间值计算完成后执行
rule "calcFinalScore"
salience 0
when
    $ctx: ScoreContext()
then
    BigDecimal total = $ctx.getIntrmdt1()
            .add($ctx.getIntrmdt2())
            .add($ctx.getIntrmdt3());
    $ctx.setFinalScore(total);
end

规则调用逻辑

// 构造业务对象和上下文对象
Person person = getPersonFromBiz();
ScoreContext scoreCtx = new ScoreContext();

// 插入工作内存
KieSession ksession = kieContainer.newKieSession();
ksession.insert(person);
ksession.insert(scoreCtx);

// 执行规则
ksession.fireAllRules();
ksession.dispose();

// 直接从上下文对象获取最终得分
BigDecimal finalScore = scoreCtx.getFinalScore();

方案2:全局变量(仅适用固定执行顺序场景)

如果不想额外定义上下文类,也可以使用Drools全局变量实现,但是注意:全局变量的变更不会被Drools推理引擎感知,仅适合你已经明确通过优先级控制了执行顺序的场景:

  1. 在DRL顶部声明全局变量,通常用Map类型存储多个中间值
  2. 触发规则前给会话设置全局变量,并写入初始值
  3. 所有规则直接读写该全局变量即可

代码示例

DRL全局变量声明

global java.util.Map scoreCache;

会话初始化时设置初始值

Map<String, Object> scoreCache = new HashMap<>();
scoreCache.put("intrmdt1", 0);
scoreCache.put("intrmdt2", 0);
scoreCache.put("intrmdt3", 0);
ksession.setGlobal("scoreCache", scoreCache);

执行顺序控制建议

  • 简单场景直接用salience属性控制优先级即可,中间值规则优先级设置高于最终得分规则
  • 规则数量多的复杂场景建议用agenda-group分组,将所有中间值计算规则归为同一分组,最终得分规则归为另一分组,代码中手动控制分组的触发顺序,逻辑更清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 09:36:03