Drools7.0 规则引擎
Drools简介
JBoss Rules 的前身是Codehaus的一个开源项目叫Drools。最近被纳入JBoss门下,更名为JBoss Rules,成为了JBoss应用服务器的规则引擎。
Drools是为Java量身定制的基于Charles Forgy的RETE算法的规则引擎的实现。具有了OO接口的RETE,使得商业规则有了更自然的表达。
Drools的用XML的
其中Java代码会使用Antlr进行解释,而Groovy和Python本身就是脚本语言,可以直接调用。
Drools的聪明之处在于,用XML节点来规范If--Then句式和事实的定义,使引擎干起活来很舒服。
而使用Java,Groovy等原生语言来做判断和执行语句,让程序员很容易过渡、移植,学习曲线很低。
Drools优点
- 非常活跃的社区支持
- 易用
- 快速的执行速度
- 在 Java 开发人员中流行
- 与 Java Rule Engine API(JSR 94)兼容
Drools相关概念
- 事实(Fact):对象之间及对象属性之间的关系
- 规则(rule):是由条件和结论构成的推理语句,一般表示为if…Then。一个规则的if部分称为LHS,then部分称为RHS。
- 模式(module):就是指IF语句的条件。这里IF条件可能是有几个更小的条件组成的大条件。模式就是指的不能在继续分割下去的最小的原子条件。
Drools通过 事实、规则和模式相互组合来完成工作,drools在开源规则引擎中使用率最广,但是在国内企业使用偏少,保险、支付行业使用稍多
Drools的基本语法
一个规则可以包含三个部分:
- 属性部分:定义当前规则执行的一些属性等,比如是否可被重复执行、过期时间、生效时间等。
- 条件部分,即LHS,定义当前规则的条件,如 when Message(); 判断当前workingMemory中是否存在Message对象。
- 结果部分,即RHS,这里可以写普通java代码,即当前规则条件满足后执行的操作,可以直接调用Fact对象的方法来操作应用。
规则示例:
rule "name"
no-loop true
lock-on-active true
when
$message:Message(status == 0)
then
System.out.println("fit");
$message.setStatus(1);
update($message);
end
- package: 与Java语言类似,drl的头部需要有package和import的声明,package不必和物理路径一致,这里只是一个逻辑区分。
- import: 导入java Bean的完整路径,也可以将Java静态方法导入调用。
- rule: 规则名称,需要保持唯一 。
- no-loop: 定义当前的规则是否允许多次循环执行,默认是 false允许循环执行,也就是当前的规则只要满足条件,可以无限次执行。在对当前传入workingMemory中的Fact对象进行修改或者个数的增减,比如update方法,这种操作会触发规则的重新匹配执行。如果是true,则规则只执行一次,如果本身的RHS部分有update等触发规则重新执行的操作,也不会再次执行当前规则。
- lock-on-active: 将lock-on-active属性的值设置为true,可避免因某些Fact对象被修改而使已经执行过的规则再次被激活执行。因为一个规则的重复执行不一定是本身触发的,也可能是其他规则触发的,所以这个是no-loop的加强版。
- date-expires:设置规则的过期时间,默认的时间格式:“日-月-年”,中英文格式相同,但是写法要用各自对应的语言,比如中文:"29-七月-2010",但是还是推荐使用更为精确和习惯的格式,这需要手动在java代码中设置当前系统的时间格式,后续提及。
- date-effective:设置规则的生效时间,时间格式同上。
- duration:规则定时,duration 3000 ,3秒后执行规则
- salience: 用来设置规则执行的优先级,salience 属性的值是一个数字,数字越大执行优先级越高, 同时它的值可以是一个负数。默认情况下,规则的 salience 默认值为 0。如果不设置规则的 salience 属性,那么执行顺序是随机的。
- when: 条件语句,就是当到达什么条件的时候执行
- then: 根据条件的结果,来执行什么动作
- end: 规则结束
规则的条件部分,即LHS部分
when
eval(true)
$customer:Customer()
$message:Message(status==0)
上述罗列了三个条件,当前规则只有在这三个条件都匹配的时候才会执行RHS部分。
- eval(true):是一个默认的api,true 无条件执行,类似于 while(true)
- $customer:Customer():表示当前的workingMemory存在Customer类
- $message:Message(status==0) 这句话标示的:当前的workingMemory存在Message类型并且status属性的值为0的Fact对象,这个对象通常是通过外部java代码插入或者自己在前面已经执行的规则的RHS部分中insert进去的。
Drools中条件操作符
Drools提供了十二中类型比较操作符:< 、<=、>、>=、==、!=、contains、not contains、memberOf、not memberOf、matches、not matches,并且这些条件都可以组合使用。
$order:Order(name=="qu")
$message:Message((status==0 || (status > 1 && status <=100)) && orders contains $order && $order.name=="qu")
- 条件组合:Message(status==0 || (status > 1 && status <=100))
- Fact对象private属性的操作:RHS中对Fact对象private属性的操作必须使用getter和setter方法,而RHS中则必须要直接用.的方法去使用,比如:$order.name=="qu"
- contains:对比是否包含操作,操作的被包含目标可以是一个复杂对象也可以是一个简单的值。 $message:Message(status==0 && names contains "网易" && names.size >= 1)。上述的条件中,status必须是0,并且names列表中含有“网易”并且列表长度大于等于1(names是一个List)。
- matches:正则表达式匹配,与java不同的是,不用考虑'/'的转义问题
- memberOf:判断某个Fact属性值是否在某个集合中,与contains不同的是他被比较的对象是一个集合,而contains被比较的对象是单个值或者对象。
注意:如果条件全部是 &&关系,可以使用“,”来替代,但是两者不能混用
规则的结果部分
当规则条件满足,则进入规则结果部分执行,结果部分可以是纯java代码,比如:
then
System.out.println("OK"); //会在控制台打印出ok
end
- insert:往当前workingMemory中插入一个新的Fact对象,会触发规则的再次执行,除非使用no-loop限定;
- update:更新
- modify:修改,与update语法不同,结果都是更新操作
- retract:删除
- function:定义一个方法,如:
function void console {
System.out.println();
StringUtils.getId();// 调用外部静态方法,StringUtils必须使用import导入,getId()必须是静态方法
}
- declare:可以在规则文件中定义一个class,使用起来跟普通java对象相似,你可以在RHS部分中new一个并且使用getter和setter方法去操作其属性。
declare Address
@author(quzishen) // 元数据,仅用于描述信息
@createTime(2011-1-24)
city : String @maxLengh(100)
postno : int
end
'@'是元数据定义,用于描述数据的数据~,没什么执行含义。
你可以在RHS部分中使用Address address = new Address()的方法来定义一个对象。
POM依赖
<!-- Drools规则引擎包 start -->
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>6.5.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>6.5.0.Final</version>
</dependency>
<!-- Drools规则引擎包 end -->
kmodule.xml
内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.drools.org/xsd/kmodule">
<kbase name="point-rulesKB" packages="rules">
<ksession name="point-rulesKS"/>
</kbase>
</kmodule>
以下对配置说明进行简单说明:
- Kmodule 中可以包含一个到多个 kbase,分别对应 drl 的规则文件。
- Kbase 需要一个唯一的 name,可以取任意字符串。
- packages 为drl文件所在resource目录下的路径。注意区分drl文件中的package与此处的package不一定相同。多个包用逗号分隔。默认情况下会扫描 resources目录下所有(包含子目录)规则文件。
- kbase的default属性,标示当前KieBase是不是默认的,如果是默认的则不用名称
就可以查找到该 KieBase,但每个 module 最多只能有一个默认 KieBase。 - kbase 下面可以有一个或多个 ksession,ksession 的 name 属性必须设置,且必须唯一。
Q.E.D.