一 前言
最早对Drools感兴趣,是起源于规则引擎.当时是希望能找一个开源工具来做一些规则的处理.
在官方网站上翻了半天资料,却发现Drools一直在强调它不只是一个简单的规则引擎,而是更多的引入工作流的概念.
之后最大的感触就是Drools牵涉到的东西比较多,甚至有一种依照Drools可以创造整个世界的感觉-- 这个世界本身不就是由各种规则/流程/事件构成的么? 这也是本文标题的由来.
以后会对Drools的各方面有一个比较深入的了解,因此这篇文章只是用来做简单的介绍,希望能在短时间内能让其他人对Drools做什么,怎么做,有一个直观的了解,以后遇到相关应用的场景时,能想到Drools的解决方案.
PS:PPT是在Team内部的团队分享时使用的,有一些链接可能会失效(外网无法访问).本文内容和PPT不会完全一致.不过问题不大了.
二.从规则引擎的应用场景说起
昨天讲解PPT的时候有人问到Drools和If-else的本质区别在哪里.我想了想,还是想引用一句话来表述自己的感受.
"南京一高职学生为了给男友发鲸鱼宝宝的短信涉嫌伪造健康证明捐精买iphone4。。。。"
2.1 各种棋类游戏
象棋围棋五子棋跳棋军棋扑克牌三国杀杀人游戏强权外交等等等等.游戏本身就是规则的代名词.
2.2 业务规则
超市打折,汇率计算等等等等.
2.3 相通的场景
这些场景可能有一些相通的点,在这儿我可能总结的不会太全面,稍稍罗列一下:
- 单条规则相对简单
- 规则数量相对庞大
- 规则之间会有冲突
- 一条规则本身会触发另一条规则
- 规则有可能会产生变动(很多时候可能唯一需要变动的就是规则)
这个时候用规则引擎来处理这些事情就相对来说容易多了.不过,Drools做的远远不止这些.
三 Drools的构成.
目前Drools的最新稳定版本是5.2.0.Final(23-Jun-2011). 现在由JBoss维护,分成五个模块.
下面就简单的介绍下每一个模块的内容,可以大致的了解下Drools的发展方向和可以用来解决问题的范畴.
3.1 Guvnor
Guvnor是一个通过Web界面可以管理,更改规则的工具,也可以提供Repository的服务.(似乎各种开源软件里都会提供这样的Web管理界面,Heritrix,Nutch,AllGeography等等等等).支持Dsl和QA.
3.2 Expert
传统的规则引擎,应该说Drools的核心,也是前身.通过Rete算法来实现模式匹配.
3.3 Jbpm5
工作流的处理交给了JBPM5这个模块.这个模块我了解的不多,大概知道的是除了工作流之外还提供了各种各样的集成(Camel,Spring,Osgi等等,感觉这个模块本身的规划不是特别清晰).其中Camel适用于路由转发.有了解的较多的朋友可以指教一下,或者以后有时间我会再了解一下相关的内容.
3.4 Fusion
用于做CEP的处理.本来是不太懂CEP的,这个概念接触的不算多.不过看到了Wiki上的一个例子,大概明白一些.
摘录如下:
Among thousands of incoming events, a monitoring system may for instance receive the following three from the same source:
1.church bells ringing.
2.the appearance of a man in a tuxedo with a woman in a flowing white gown.
3.rice flying through the air.
From these events the monitoring system may infer a complex event: a wedding
3.5 Planner
Planer用来解决一系列的问题,如N皇后问题,TSP
(话说这些问题有什么共同点我还没有领会得到,大体的感觉是可以用来解决一些规划问题,或者是说求解问题).
3.6 关系图
这是我理解的关系图.
Expert还是核心,Fusion和Planer和Workflow都应该是规则的应用到具体领域的扩展,通过JBPM5还提供了和各种开源软件的集成.Guvnor来提供各种资源的管理.
四 Expert
对Expert有了解就可以使用Drools了.所以我想还是总体的介绍下Expert的使用,这样具体的细节其他朋友可以通过翻阅手册来自己解决了.
列出几个知识点:
1.Drl文件.
Drl就是Drools用来描述规则的文件.DRL文件的结构包括以下几部分:
package package-name
imports
globals
functions
queries
rules
Drl中可以通过Import的方式引入Model类,也可以调用Java的各种函数.
Drl中也可以自己定义Class和Function.
Queries的应用场景还不太了解,目前没有用到过.
Rules就是规则的部分,它的结构如下:
rule "name"
attributes
when
LHS(The Rule Language)
then
RHS(Java,Pthyon,Groovy)
end
每一条规则都有名称.
每一条规则都有属性(lock-on-active等)
When里写的是LHS(Left Hand Side,左手边),等同于IF里的条件判断.左手边是Drools自己的语法规则,详见Drools的文档.
Then里写的是RHS(Right Hand Side,右手边),等同于IF里的执行语句.右手边支持多种语言(Java,Pthyon,Groovy等).
2.规则文件的使用
- KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
- kbuilder.add(ResourceFactory.newClassPathResource("demo.drl"), ResourceType.DRL);
- KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
- kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
- StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
- Employee employee=new Employee("段三品");
- employee.setClockedAt(System.currentTimeMillis());
- ksession.insert(employee);
- ksession.fireAllRules();
Session分成两种,一种是StateFul,一种是StateLess.区别是StateFul是可以完成推理的,即一条规则有可能导致另一条规则的触发,因此需要显示的调用一下FireAllRules().而StateLess是不支持规则推理的.所以规则是自动触发.
Employee 是一个简单的Demo类,用来表示一个员工.这里想给出的是一个判断员工上班是否迟到的示例,因此Employee可以设计成这个样子.
- import java.io.Serializable;
- import org.apache.commons.lang.builder.ToStringBuilder;
- import org.apache.commons.lang.builder.ToStringStyle;
- public class Employee implements Serializable{
- /**
- *
- */
- private static final long serialVersionUID = -2301765612395462099L;
- private String name;
- private Long clockedAt;
- private boolean late;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Long getClockedAt() {
- return clockedAt;
- }
- public void setClockedAt(Long clockedAt) {
- this.clockedAt = clockedAt;
- }
- public boolean isLate() {
- return late;
- }
- public void setLate(boolean late) {
- this.late = late;
- }
- public String toString() {
- return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
- }
- }
假设公司的迟到规则是九点钟以后打卡就算迟到,那么规则就可以写成这样子.
- rule "迟到"
- lock-on-active
- when
- $employee: Employee(clockedAt > 9:00 )
- then
- $employee.setLate(true);
- end
将一个Model Insert进去,调用FireAllRules方法,就是执行了规则,Model的值就会发生改变.
这就是Expert使用的最简单的方式.
3.产生式系统
规则引擎里的一些术语是来自于产生式系统的.如LHS,RHS,Fact,ProductMemory,WorkingMemory.
LHS和RHS之前已经提到过,下面来介绍一下其它的术语.
Fact:每一条规则称之为Fact.
ProductMemory:保存Fact.如上例说到的迟到的规则.
WorkingMemory:保存每一个实例,如上例说到的每一个员工.
可以把规则引擎理成一个WorkingMemeory和ProductMemory的模式匹配.有四种算法.(Linear,Rete,Treat,Leap).
Drools使用的是Rete.据说也有Leap的实现,后来因为无人使用也无人维护给放弃了.
4.Rete
Rete是网络的意思,简单的说,Rete算法的思路就是事先将Fact构建成一个过滤网,这个过滤网由四种节点构成.分别是Root,1-input(alpha),2-input(beta),terminal.
这四个节点也比较简单,Root是入口,所有的实例都从Root出进入Rete.Alpha用来做Literal的验证(如"Name=段三品"),Beta节点用来做对象的验证,如(employee1=employee2),terminal是终止节点.
一直在想一个简单的方式能描述Rete做的功能.可以想象成从Root到Aplpha到Beta到Terminal是由不同的阀门构成的水管.
从Root处开始往下倒各种液体(水,酒,醋等等,等同于WorkingMemory的一个个实例),对于各个节点来说,如果满足自己的验证条件,那么就可以放行.如果不满足,就不通过.这样最后从Terminal流出的就是匹配到的规则.
昨天又有人问到这个和有限状态自动机的区别是什么.我想区别就在于每一个节点都保留了符合这个节点的WorkingMemory.而有限状态自动机是不会保存这些内容的.
以上是对Rete的简单理解,希望能有朋友多指教.
符上一张图(很遗憾忘记在哪儿粘过来的了,对原图的作者表示歉意).
五 Guvnor
Guvnor这部分,我想说的主要是关于Dsl的部分.
Dsl其实大部分人已经经常用到了.只不过自己还不知道而已.如Shell,Uml,Sql,wiki Template.
Guvnor支持Dsl的配置,DSL configurations的选项里可以新建,编辑Dsl文件.这里给出一个Guvnor安装后自带的例子.
- [when]When the credit rating is {rating:ENUM:Applicant.creditRating} = applicant:Applicant(creditRating=="{rating}")
- [then]Approve the loan = applicant.setApproved(true)
- [when]When the applicant dates is after {dos:DATE:default} = applicant:Applicant(applicationDate>"{dos}")
- [when]When the applicant approval is {bool:BOOLEAN:checked} = applicant:Applicant(approved=={bool})
- [when]When the ages is less than {num:1?[0-9]?[0-9]} = applicant:Applicant(age<{num})
这样在编辑规则的时候.就可以用Dsl语言去编写规则了.有助于将业务逻辑从代码中分离出去.将变化和非变化的部分分离开来.
六. 小结
Drools对于规则的理解更深入,或者说是对于规则的应用理解更深入.当然这个世界是由什么来构成的,不可能有一个准确又有用的答案.可是至少在Drools的眼里,世界可以由规则组成.
有太多的内容没有涉及到了,所以还是希望这篇文章能够做到之前对Drools给出一个感性的认识,知道Drools能做什么事情,了解Drools怎么去做的.以后再面对项目需求时,在可以用到Drools的场景下,再去详细查证手册好了.
另外Drools的安装包本身包含大量的示例程序.Reference做的也相当不错.都是很好的资料.