规则引擎Drools

来源:互联网 发布:互联网 大数据征文 编辑:程序博客网 时间:2024/06/11 22:23


1. 规则引擎


规则引擎是一种嵌套在应用程序中的组件,它实现了将业务规则从应用程序代码中分离出来。规则引擎使用特定的语法编写业务规则,规则引擎可以接受数据输入、解释业务规则、并根据业务规则做出相应的决策。


引入规则引擎后带来的好处:

实现业务逻辑与业务规则的分离,实现业务规则的集中管理
可以动态修改业务规则,从而快速响应需求变更
使业务分析人员也可以参与编辑、维护系统的业务规则
使用规则引擎提供的规则编辑工具,使复杂的业务规则实现变得的简单


2. 适合使用规则引擎的场景

case 1: 有一定量的业务逻辑处理,很多应用随着时间推移越来越复杂,逻辑引擎可以更轻松应对。

只是把数据从数据库中读出写入,就不要使用规则引擎。

case 2: application生命周期长适于规则引擎,短则不适合。

case 3: 业务需求频繁变化适合使用规则引擎,否则不成立。


3. Drools

开源规则引擎的代表是Drools,商业规则引擎的代表是ILog。Drools是Jboss公司旗下一款开源的规则引擎,它完整的实现了Rete算法;提供了强大的Eclipse Plugin开发支持;通过使用其中的DSL(Domain Specific Language),可以实现用自然语言方式来描述业务规则,使得业务分析人员也可以看懂业务规则代码。

3.1 Rete算法 

RETE算法是一个用来实现产生式规则系统的高效模式匹配算法。它从一个初始的事实出发,不断地应用规则得出结论(或执行指定的动作)。

3.2 规则的工作流程  

推理引擎包括三部分:Pattern Matcher、Agenda和Execution Engine。推理引擎通过Pattern Matcher决定执行哪些满足事实或目的规则,并授予规则优先级,这些规则被加入AgendaAgenda管理Pattern Matcher挑选出来的规则的执行次序;Execution Engine擎负责执行规则和其他动作。 

step 1. 将初始数据fact输入Working Memory。 
step 2. 使用Pattern Matcher比较rule base中的rule和fact。

step 3. 如果rule存在冲突conflict,即同时激活了多个规则,将冲突的规则放入冲突集合。    

step 4. 解决冲突,将激活的规则按顺序放入Agenda。   

step 5. 使用Execution Engine执行Agenda中的规则。

重复步骤2至5,直到执行完毕所有Agenda中的规则。


4. Drools开发

4.1 规则

4.1.1 规则文件以.drl结尾,可以存放多个规则,还可以存放被规则使用的用户自定义的函数、数据对象及自定义查询等, 对于同一package 下的用户自定义函数、自定义的查询等,不管这些函数与查询是否在同一个规则文件里面,在规则里面是可以直接使用。

package package-name ,声明package在规则文件中是必要的

imports 

globals 

functions 

queries 

rules 

e.g.

package storm.cookbook.log.rules

import storm.cookbook.log.model.LogEntry;
import java.util.regex.Matcher
import java.util.regex.Pattern

rule "Host Correction"

    when
        l: LogEntry(sourceHost == "localhost")
    then
        l.setSourceHost("localhost.example.com");
end

4.1.2 一个rule通常包括三个部分:属性部分(attribute)、条件部分(LHS)和结果部分(RHS)。对于一个完整的规则来说,这三个部分都是可选的。

LHS 部分是由一个或多个条件组成,条件又称之为pattern(匹配模式),多个pattern之间用可以使用and 或or 来进行连接,同时还可以使用小括号来确定pattern 的优先级。 

RHS 为条件满足触发的动作,可以使用LHS 部分当中定义的绑定变量名、设置的全局变量、或者是直接编写Java 代码(import 引入的Java类)

规则属性是用来控制规则执行的重要工具,在目前的Drools5当中,规则的属性共有13个,它们分别是:activation-group、agenda-group、auto-focus、date-effective、date-expires、dialect、duration、enabled、lock-on-active、no-loop、ruleflow-group、salience、when

salience:用来设置规则执行的优先级,salience属性的值是一个数字,数字越大执行优先级越高,同时它的值可以是一个负数。默认情况下,规则的salience默认值为0。

no-loop:   在条件满足时,对Working Memory当中的某个Fact对象进行了修改,将其更新到当前的Working Memory中,这时引擎会再次检查所有的规则是否满足条件,no-loop属性控制如果满足是否会再次执行。no-loop属性的值是一个布尔型,默认为false。

date-effective: 当系统时间>=date-effective设置的时间值时,规则才会触发,否则规则将不执行。若没有设置该属性,规则将随时触发。该属性的值是一个日期类型,默认格式是”dd-MMM-yyyy”。可以通过设置改变格式。

date-expires: 如果系统时间<date-expires设置的时间值,那么规则将执行,否则就不执行。

activation-group: 将若干个规则划分成一个组,具有相同activation-group属性的规则只要有一个被执行,其它的规则都将不再执行。规则当中究竟哪一个会先执行,可以用类似salience之类属性来实现。

agenda-group: 规则的调用与执行是通过StatelessSession或StatefulSession来实现的,一般的顺序是创建一个StatelessSession或StatefulSession,将各种经过编译的规则的package添加到session当中,接下来规则当中可能用的Global对象和Fact对象插入到Session当中,最后调用fireAllRules方法来执行,在调用fireAllRules方法之前,所有的规则及插入的Fact对象都存放在一个名叫Agenda表的对象当中。agenda-group是用来在Agenda的基础上,对现的规则进行再次分组。Agenda-group属性的值也是一个字符串,引擎在调用这些设置了agenda-group属性的规则的时候需要显示的指定某个Agenda Group得到Focus(焦点),这样位于Agenda Group当中的规则才会触发执行,否则将不执行。

auto-focus:  在agenda-group的规则上设置该规则是否可以自动读取Focus,如果该属性设置为true,则在引擎执行时,不需要显示的为某个Agenda Group设置Focus,否则需要。

dialect:  定义规则当中要使用的语言类型,目前Drools5版本当中支持两种类型的语言:mvel和java,默认情况下,如果没有手工设置规则的dialect,那么使用的是java语言。

duration:  对于一个规则来说,如果设置了该属性,那么规则将在该属性指定的值之后在另外一个线程里触发。该属性对应的值为一个长整型,单位是毫秒。

enabled: 定义一个规则是否可用的, 该属性的值是一个布尔值,默认为true,表示规则是可用的。如果手工为一个规则添加一个enabled属性,并且该属性值为false,那么引擎就不会执行该规则。

e.g.

rule "rule1"

   salience 1 / duration 3000

   when 

       eval(true)

  then

       System.out.println("rule1");


4.2  Java程序开发

在Drools当中,规则的编译与运行要通过Drools提供的各种API来实现,这些API总体来讲可以分为三类:规则编译、规则收集和规则的执行。完成这些工作的API主要有KnowledgeBuilder、KnowledgeBase、StatefulKnowledgeSession、StatelessKnowledgeSession等,它们起到了对规则文件进行收集、编译、查错、插入fact、设置global、执行规则或规则流等作用,在正式接触各种类型的规则文件编写方式及语法讲解之前,我们有必要先熟悉一下这些API的基本含义及使用方法。

4.2.1 KnowledgeBuilder

规则编写完成之后,接下来的工作就是在应用的代码当中调用这些规则,利用这些编写好的规则帮助我们处理业务问题。KnowledgeBuilder 的作用就是用来在业务代码当中收集已经编写好的规则, 然后对这些规则文件进行编译, 最终产生一批编译好的规则包(KnowledgePackage)给其它的应用程序使用。KnowledgeBuilder 在编译规则的时候可以通 过其提供的hasErrors()方法得到编译规则过程中发现规则是否有错误,如果有的话通过其提 供的getErrors()方法将错误打印出来,以帮助我们找到规则当中的错误信息。

通过KnowledgeBuilder编译的规则文件的类型可以有很多种,如.drl文件、.dslr文件或一个xls文件等。产生的规则包可以是具体的规则文件形成的,也可以是规则流(rule flow)文件形成的,在添加规则文件时,需要通过使用ResourceType的枚举值来指定规则文件的类型;同时在指定规则文件的时候drools还提供了一个名为ResourceFactory的对象,通过该对象可以实现从Classpath、URL、File、ByteArray、Reader或诸如XLS的二进制文件里添加载规则。

创建KnowledgeBuilder 对象使用的是KnowledgeBuilderFactory 的newKnowledgeBuilder方法。以下是代码 
         
kbuilder.add(ResourceFactory.newClassPathResource("Sample.drl"), ResourceType.DRL);           

KnowledgeBuilderErrors errors = kbuilder.getErrors();              

if (errors.size() > 0) { 
                  for (KnowledgeBuilderError error : errors) {                        

                                         System.err.println(error);                  

                  } 
                  throw new IllegalArgumentException("Could not parse knowledge."); 
 

Collection<KnowledgePackage>  kpackage=kbuilder.getKnowledgePackages();//产生规则包的集合

4.2.2 KnowledgeBase 

KnowledgeBase 是Drools 提供的用来收集应用当中知识(knowledge)定义的知识库对象,在一个KnowledgeBase 当中可以包含普通的规则(rule)、规则流(rule flow)、函数定义(function)、用户自定义对象(type model)等。KnowledgeBase 本身不包含任何业务数据对象,业务对象都是插入到由KnowledgeBase产生的两种类型的session 对象当中,通过session 对象可以触发规则执行或开始一个规则流执行。 
创建一个KnowledgeBase 要通过KnowledgeBaseFactory 对象提供的newKnowledgeBase()方法来实现。
KnowledgeBase kbase=KnowledgeBaseFactory.newKnowledgeBase();  

创建的时候还可以为其指定一个KnowledgeBaseConfiguration对象,KnowledgeBaseConfiguration对象是一个用来存放规则引擎运行时相关环境参数定义的配置对象。

KnowledgeBaseConfiguration kbConf = KnowledgeBaseFactory.newKnowledgeBaseConfiguration(); 
kbConf.setProperty( "org.drools.sequential", "true");   

KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(kbConf);
KnowledgeBase 创建完成之后,接下来就可以将我们前面使用KnowledgeBuilder 生成的KnowledgePackage 的集合添加到KnowledgeBase 当中,以备使用,以下是代码 kbase.addKnowledgePackages(kpackage);

4.2.3 StatefulKnowledgeSession 
规则编译完成之后,接下来就需要使用一个API 使编译好的规则包文件在规则引擎当中运行起来。在Drools5 当中提供了两个对象与规则引擎进行交互:StatefulKnowledgeSession和StatelessKnowledgeSession。 
StatefulKnowledgeSession 对象是一种最常用的与规则引擎进行交互的方式,它可以与规则引擎建立一个持续的交互通道,在推理计算的过程当中可能会多次触发同一数据集。在用户的代码当中,最后使用完StatefulKnowledgeSession 对象之后,一定要调用其dispose()方法以释放相关内存资源。 
StatefulKnowledgeSession 可以接受外部插入(insert)的业务数据——也叫fact,一个fact 对象通常是一个普通的Java 的POJO,一般它们会有若干个属性,每一个属性都会对应getter 和setter 方法,用来对外提供数据的设置与访问。一般来说,在Drools 规则引擎当中,fact 所承担的作用就是将规则当中要用到的业务数据从应用当中传入进来,对于规则当中产生的数据及状态的变化通常不用fact 传出。如果在规则当中需要有数据传出,那么可以通过在StatefulKnowledgeSession 当中设置global 对象来实现,一个global 对象也是一个普通的Java 对象,在向StatefulKnowledgeSession 当中设置global 对象时不用insert 方法而用setGlobal 方法实现。创建一个StatefulKnowledgeSession 要通过KnowledgeBase 对象来实现,以下是代码 
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession(); 

KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test"); 
   // go ! 
Message message = new Message();    

message.setMessage("Hello World");    

message.setStatus(Message.HELLO);    

ksession.insert(message);  
ksession.fireAllRules();  
logger.close(); 

ksession.dispose(); 
上面的所有代码表示了规则完整的运行处理过程,可以看到,它的过程是首先需要通过使用KnowledgeBuilder 将相关的规则文件进行编译,产生对应的KnowledgePackage集合,接下来再通过KnowledgeBase 把产生的KnowledgePackage 集合收集起来,最后再产生StatefulKnowledgeSession 将规则当中需要使用的fact 对象插入进去、将规则当中需要用到的global 设置进去,然后调用fireAllRules()方法触发所有的规则执行,最后调用dispose()方法将内存资源释放。

4.2.4 StatelessKnowledgeSession 
StatelessKnowledgeSession 的作用与StatefulKnowledgeSession 相仿,它们都是用来接收业务数据、执行规则的。事实上,StatelessKnowledgeSession 对StatefulKnowledgeSession 做了包装,使得在使用StatelessKnowledgeSession 对象时不需要再调用dispose()方法释放内存资源了。因为StatelessKnowledgeSession 本身所具有的一些特性,决定了它的使用有一定的局限性。在使用StatelessKnowledgeSession 时不能进行重复插入fact 的操作、也不能重复的调用fireAllRules()方法来执行所有的规则,对应这些要完成的工作StatelessKnowledgeSession当中只有execute(…)方法,通过这个方法可以实现插入所有的fact 并且可以同时执行所有的规则或规则流,事实上也就是在执行execute(…)方法的时候就在StatelessKnowledgeSession内部执行了insert()方法、fireAllRules()方法和dispose()方法。以下是使用代码 
StatelessKnowledgeSession  statelessKSession=kbase.newStatelessKnowledgeSession(); 

ArrayList list=new ArrayList(); 

list.add(new Object());

list.add(new Object());

statelessKSession.execute(list); 

4.2.5 Fact 
Fact 是指在Drools 规则应用当中,将一个普通的JavaBean 插入到规则的WorkingMemory当中后的对象。规则可以对Fact 对象进行任意的读写操作,当一个JavaBean 插入到WorkingMemory 当中变成Fact 之后,Fact 对象不是对原来的JavaBean 对象进行Clon,而是原来JavaBean 对象的引用。规则在进行计算的时候需要用到应用系统当中的数据,这些数据设置在Fact 对象当中,然后将其插入到规则的WorkingMemory 当中,这样在规则当中就可以通过对Fact 对象数据的读写,从而实现对应用数据的读写操作。一个Fact 对象通常是一个具有getter 和setter 方法的POJO 对象,通过这些getter 和setter 方法可以方便的实现对Fact 对象的读写操作,所以我们可以简单的把Fact 对象理解为规则与应用系统数据交互的桥梁或通道。当 Fact 对象插入到WorkingMemory 当中后,会与当前WorkingMemory 当中所有的规则进行匹配,同时返回一个FactHandler 对象。FactHandler 对象是插入到WorkingMemory当中Fact 对象的引用句柄,通过FactHandler 对象可以实现对对应的Fact 对象的删除及修改等操作。 
在前面介绍StatefulKnowledgeSession 和StatelessKnowledgeSession 两个对象的时候也提到了插入Fact 对象的方法,在StatefulKnowledgeSession 当中直接使用insert 方法就可以将一个Java 对象插入到WokingMemory 当中,如果有多个Fact 需要插入,那么多个调用insert方法即可;对于StatelessKnowledgeSession 对象可利用CommandFactory 实现单个Fact 对象或多个Fact 对象的插入。



0 0
原创粉丝点击