网站:http://labs.jboss.com/jbossrules
完整文档:http://labs.jboss.com/portal/jbossrules/docs/index.html
详细的文档中文翻译与学习笔记:http://www.blogjava.net/guangnian0412/
Drools 变身为JBoss Rules 3.0后已经拥有了好得多规则语法,平民级的DSL语言和基于Eclipse的编辑器,前景明亮。
其中平民级的DSL语法促使规则引擎这个有点神秘的高端很有机会在2007年大面积应用于各个普通开发团队,如Spring,Hibernate一样平常。
Drools下载中有一个Samples下载包有完整的demo代码,SpringSide中主要应用Drools作订单计价。
1. 从Drl规则文件编译得到RuleBase--编译后的规则集;
2. 从RuleBase生成本次规则运算的场地--WorkingMemory;
3. 将规则运算用到的事实放入WorkingMemory;
4. FireAll Rules,对事实进行规则运算。
不再同以前的XML版语法,现在的[When] 结构中,When节点包含了autoboxing等简化语法,没有Java原版equals语法的冗长。
一个完整的drl 文件如下:
/*
* multi comments
*/
package org.springside.rules.orderPricing
import org.springside.facts.factsObject
expander another_drl_or_dsl_files
// some comments
rule "rule_name"
agenda-group "group_name"
salience -1
no-loop false
auto-focus false
activation-group "xor_group_name"
duration 0
#some comments
when
order : Order( totalPrice >= 100)
then
order.setDiscountPrice(new Double(order.getTotalPrice().doubleValue() * 0.9));
end
具体的drl 属性定义,请查阅drools 官方网站文档。
这里需要注意的是:then 子句中为纯粹的java 表达式,所以每句必须要以";"
结束。而在其他的地方可以不用。
同时,你也可以选用JavaScript解释引擎,在then子句中使用JavaScript语法
Drools的DSL采用了直接映射而不是Yacc,Antrl之类的语义分析是我最喜欢的地方,唯有如此,普通团队才可以用上对客户充满诱惑,对团队本身也能清晰定义的DSL, 而且,这DSL还能获得Eclipse插件的支持
只要声明一个DSL映射文件
[when]order price larger than {topPrice}=order : Order( totalPrice >= {topPrice} )
#如果多行,可以在第一行用"/" 进行换行
[then]do {discountRate}discount= order.setDiscountPrice/(new Double(order.getTotalPrice().doubleValue() * {discountRate}));
就可以这样使用
expander orderPricing.dsl
rule "discount order"
when
order price larger than 100
then
do 0.9 discount
end
具体的使用,可以查看官方文档。这里Drools 有点取巧,它是首先读取Excel 文件,把每一行决策作为一个Rule。然后把Excel 文件转换成drl 格式的文本,再调用drl 规则的API 构建规则的。并且,在Excel 文件中定义的Rule 是有执行顺序的。它会按照行数由上自下执行。
[TODO]:
3.0 相对于2.5 以来,在效率方面有了大大的提升。现在的规则执行速度上面已经基本上达到了JRule6 的水平。
对于执行效率,有几点需要注意的地方:
1、Condition 的排放顺序。如果你的规则中Condition 不只一个的话,那么把哪个Condition 放在前面是很有讲究的,这直接关系到规则引擎的执行效率。
例如下面,有上万个如下类型的facts 将同时assert 进入规则引擎中参与计算。而这些facts 中绝大部分facts 的type 为1,name 却各不相同:
/*
* fact class
*/
public class FactObject {
private int type;
private String name;
// 省去getter/setter Methods
}
规则文件如下定义:
when
fact : FactObject(type == 1, name == "test")
和这样定义:
when
fact : FactObject(name == "test", type == 1)
后面这种定义相对于前面,单单是换了一个顺序,在执行效率方面相差几十倍!其原理和数据库索引的原因相似。
2、还是如上面的这个例子,对于字符串,如果在比较之前使用intern() 的话,那么效率也会部分提升。
参见JBoss Wiki:http://wiki.jboss.org/wiki/Wiki.jsp?page=StringIntern
1、这里最需要注意的是Drools 最严重的一个Bug:关键字冲突。如果使用了任何与关键字相同的名称,包含包名、组名、dsl 定义中的单词,以及函数名称,那么这个drl 文件将会在构建时候报错。包含这样的使用:package org.springside.rule
现把Drools 的所有关键字列出:
when then rule end contains matches and or modify
retract assert salience function
query exists eval agenda-group no-loop
duration -> not auto-focus
这个Bug 将在Drools 3.1M1 中解决。
2、在dsl 定义中,不能使用标点。如:Order's
price larger than 100。这样的定义也无法被编译。
SpringSide对单次执行的规则进行了简单封装, 让用户可以用一句API调用就使用到规则引擎.
而对于复杂的规则引擎API使用, SpringSide将只返回WorkingMemory或RuleBase, 让用户自行调用JBoss Rules的原版API,思路和Spring对Hibernate的封装,关键时候返回sessionFactory让用户自行调用一样.
不得不说,drools 自3.0 后对于规则的管理大大加强了,这也是springside 将drools 升级到3.0 后,放弃数据库管理模块的一个原因。
在2.5 中,我们是通过每一个规则文件,都构建一个RuleBase 来对规则进行分组以及管理的。但是自从进入3.0 后,我们只存在一个RuleBase 。而每个drl 文件上定义的package 将作为Rule 管理的基本单元,每个Rule 中的属性agenda-group 将作为规则分组的基本单元。
将Drools的底层代码全部封装起来,只留一个RuleSTemplate接口,有如下函数:
public List executeRules(List facts, String groupName, String ruleNameFilter)
第一个参数--参与规则运算的事实表;
第二个参数--所调用的规则集名称,对应的为drl 文件中rule 的agenda-filter 属性。如果用null
则表示不限定规则集,fire 所有的规则。另外,在agenda-filter 中有一个默认的规则组“MAIN”,在此参数中,使用"MAIN" 和
null 等同。
第三个参数--规则名称过滤,现使用的为StartsWith 规则,也就是规则名称starts with the ruleNameFilter,
此规则才会被fire 。如果有需要,可以通过修改ss 的DroolsTemplate 文件获得不同的规则名称过滤。如果为null 则表示不对规则名称过滤。
用户使用时只需参照ApplicationContext-rule.xml 配置一把,就能在代码里使用简单的RuleTemplate接口进行规则运算。
DroolsTemplate 支持从数据库或drl文件中获得规则,只需为DroolsTemplate注入不同的RuleLoader即可。
<bean id="dslRuleBaseLoader" class="org.springside.modules.rule.support.DSLRuleBaseLoader">
<property name="ruleFiles" value="classpath*:rules/dsl/**.drl"/>
<property name="dslFile" value="/rules/dsl/orderPricing.dsl"/>
</bean>
<bean id="ruleTemplate" class="org.springside.modules.rule.support.RuleTemplateImpl">
<property name="ruleBaseLoader" ref="dslRuleBaseLoader"/>
</bean>
留意DSLRuleBaseLoader的配置,使用Spring Style的文件名称匹配。
Drools 可以说是开源的规则引擎中最好的一个了。springside 中,只是用了Drools 中通用的部分。相信大家如果深入的去研究的话,肯定每次都会有新的发现:)