4. 第一个Champion规则:创建最简单的规则文件(.drl格式)、规则语法结构(rule/condition/action)、加载规则并执行

本章将带领你从零创建第一个Champion规则文件,理解.drl格式的核心语法结构,并通过Python代码加载规则并执行。这是后续所有规则开发的基础,请务必动手完成每一步。

4.1 .drl规则文件格式

.drl(Drools Rule Language)是Drools规则引擎的标准规则文件格式,本质上是纯文本文件,使用.drl作为扩展名。一个最简单的.drl文件包含以下基本要素:

要素 说明 示例
package 规则包声明,用于逻辑分组(可选但推荐) package com.champion.rules
import 导入Java/Python类或数据类型 import com.champion.model.Order
rule 规则定义块,包含名称、条件、动作 rule "HelloWorld"
when 条件部分(LHS),匹配事实 when $o: Order(amount > 100)
then 动作部分(RHS),执行逻辑 then System.out.println("大额订单");
💡 提示:在Champion实验环境中,.drl文件使用UTF-8编码,文件名建议使用英文小写+下划线,例如 first_rule.drl。

4.2 规则语法结构:rule / condition / action

每个规则由三个核心部分组成,遵循“当条件满足时执行动作”的范式:

  • rule 名称:规则唯一标识,用双引号包裹,如 rule "CheckDiscount"
  • when(条件):定义触发规则的条件表达式,支持逻辑运算符(&&、||、!)和模式匹配
  • then(动作):条件满足时执行的代码块,可以修改事实、输出日志、调用外部服务等

下面是一个完整的.drl文件示例,包含一个简单的规则:

package champion.demo

// 导入Python对象(在Champion中通过桥接层支持)
import champion.model.Person

rule "AdultCheck"
    when
        $p: Person(age >= 18)
    then
        System.out.println($p.getName() + " 是成年人");
        $p.setAdult(true);
end
📌 关键点:
  • 规则以 rule "名称" 开始,以 end 结束
  • when 和 then 之间不要有空行(语法要求)
  • 条件中的变量绑定使用 $变量名: 格式,如 $p: Person(...)
  • 动作部分支持Java语法(Champion引擎内部基于Java实现)

4.3 加载规则并执行

在Champion实验环境中,我们使用Python代码加载.drl文件、创建规则引擎会话并执行规则。以下是完整的操作流程:

  1. 准备.drl文件:将规则文件放置在项目目录(如 rules/ 文件夹)
  2. 初始化规则引擎:创建KieContainer并读取规则库
  3. 插入事实对象:将需要匹配的数据对象插入工作内存
  4. 触发规则:调用 fireAllRules() 执行匹配的规则
  5. 获取结果:从事实对象中读取规则执行后的状态变化

下面是一个完整的Python执行脚本示例:

# champion_execute.py
from champion import KieServices, KieHelper
from champion.model import Person

# 1. 加载规则文件
ks = KieServices.Factory.get()
kcontainer = ks.newKieContainer(
    ks.newReleaseId("champion", "demo-rules", "1.0.0")
)

# 或者使用KieHelper直接加载.drl文件
kh = KieHelper()
kh.addResource("rules/first_rule.drl")
kbase = kh.build()
ksession = kbase.newKieSession()

# 2. 创建事实对象
person = Person(name="张三", age=25, adult=False)

# 3. 插入事实
ksession.insert(person)

# 4. 执行规则
ksession.fireAllRules()

# 5. 输出结果
print(f"姓名: {person.getName()}")
print(f"年龄: {person.getAge()}")
print(f"是否成年人: {person.isAdult()}")

# 6. 释放资源
ksession.dispose()
⚠️ 常见错误:
  • 忘记调用 dispose() 导致内存泄漏
  • 事实对象未正确设置getter/setter方法
  • .drl文件中类名或包名与Python模型不一致

4.4 规则执行流程SVG图

下图展示了从加载规则文件到执行完成的完整数据流:

规则执行流程 .drl 规则文件 KieHelper 加载 KieBase 规则库 insert(事实对象) fireAllRules() 获取结果/输出 说明 1. 规则文件→加载→ 规则库 2. 事实插入+触发→ 规则匹配执行

4.5 规则语法对比表

为了帮助你快速区分.drl规则中的不同语法元素,下表列出了常见模式及其含义:

语法模式 含义 示例
$var: ClassName( field == value ) 绑定变量并匹配字段等于某值 $o: Order( status == "NEW" )
$var: ClassName( field > value ) 匹配字段大于某值 $p: Person( age > 18 )
not ClassName( ... ) 不存在匹配的事实 not Person( name == "admin" )
exists ClassName( ... ) 至少存在一个匹配的事实 exists Order( amount > 1000 )
eval( 表达式 ) 执行任意布尔表达式 eval( $p.getAge() >= 18 )

4.6 动手实验:创建并运行第一个规则

按照以下步骤完成你的第一个Champion规则实验:

  1. 创建项目结构:在 champion_workspace/ 下新建 rules/ 文件夹
  2. 编写规则文件:在 rules/ 中创建 hello_champion.drl,内容如下:
package champion.hello

rule "SayHello"
    when
        $msg: String(this == "champion")
    then
        System.out.println("Hello, Champion Rule Engine!");
end
  1. 编写Python执行脚本:创建 run_hello.py:
from champion import KieHelper

kh = KieHelper()
kh.addResource("rules/hello_champion.drl")
kbase = kh.build()
ksession = kbase.newKieSession()

ksession.insert("champion")
ksession.fireAllRules()
ksession.dispose()
  1. 运行脚本:在终端执行 python run_hello.py,控制台应输出 Hello, Champion Rule Engine!
✅ 验证成功:如果看到上述输出,说明你的第一个Champion规则已经成功加载并执行!这是你掌握规则引擎的里程碑。

4.7 规则文件与执行架构SVG图

下图展示了Champion规则引擎的组件架构及数据流向:

Champion规则引擎架构 Python 应用层 Python 事实对象 KieHelper API KieSession fireAllRules() 结果回调 Champion 引擎内核 规则编译器 Rete 网络 议程(Agenda) 规则执行器 工作内存 数据流说明 1. Python插入事实→工作内存 2. 调用fireAllRules→议程 3. 规则执行→结果返回Python

4.8 常见问题与排错

问题现象 可能原因 解决方案
规则未触发 条件不匹配或事实未插入 检查 insert() 是否调用,条件表达式是否正确
ClassNotFoundException 模型类未导入或路径错误 确认 import 语句中的类名与Python模型一致
语法错误 .drl文件格式错误 检查 when/then 缩进,确保 end 存在
内存泄漏 未调用 dispose() 在 finally 块中释放KieSession
📘 本章小结:
  • .drl文件是规则引擎的规则定义文件,包含package、import、rule等要素
  • 规则结构为 rule "名称" when 条件 then 动作 end
  • Python通过KieHelper加载.drl文件,创建KieSession,插入事实并调用fireAllRules()
  • 规则执行流程:加载→编译→匹配→触发→输出