Drools

1.2为什么使用规则引擎
一些经常会问到的问题有:
。为什么我要用一个规则引擎?
。相比"if ...then"这样的硬编码规则的方法,规则引擎有什么优点?
。为什么我要规则引擎,而不是像Beanshell之类的脚本框架?
我们将在下面解答这些
1.2.1 规则引擎的优点总结
。声明式编程
规则引擎可以允许你只需要说“要做什么”,而不是说“如何去做”。
这样做的很重要的优点是很容易的表达困难问题的解答,从而对结果进行验证(阅读规则比阅读代码容易的多)
规则系统能够解决非常非常困难的问题,同时提供的这种解决还能够解释为什么会有这样的决策(别的AI系统就很不容易,像神经网络,或者说我的大脑-我不知道我为什么能画出汽车)
。逻辑和数据的分离
你的数据在你的域对象中,逻辑在规则中。这将根本上打破OO中数据和逻辑的绑定(依赖于你的观点,这是个优点或许是个缺点)。结果是逻辑能更加容易的维护,更容易在未来进行改变,因为逻辑是建立在规则之上的。
。速度和可扩展性
Rete算法,Leaps算法和它的派生算法,例如Drools的Reteoo(和leaps),提供了非常有效的方法去匹配规则模式和数据对象数据。特别是当你数据集不会完全改变的适合就更加有效(规则引擎能够记住过去的匹配)。这些算法经历了实战的检验。
。以知识为中心
通过运用规则,你能够建立可执行的知识库。This means its a single point of truth, for business policy (for instance),理想的,规则是如此的具有可读性,除了执行它们也可以作为文档。
。工具集成
像eclipse(以后会是基于web的UI)这样的工具提供了方法来编辑和管理规则,得到即时反馈,验证,content assitance,审计和调试工具。
。explanation facility
规则系统能够通过记录规则引擎的决策,有效的提供“explanation facility”
。可理解规则(能够由领域专家阅读)
通过创建对象模型(可选的,域特定的语言),建模你的问题域,规则看起来非常贴近自然语言。这使得那些不是技术人员的领域专家能够理解。
1.2.2 什么时候你应该采用规则引擎
对于这个问题最简单的回答是“当传统的编程方法没有可以令人满意的方法解决问题的时候”。对这个简单的回答需要我们做出详细的解释。
没有传统办法的原因可能是以下原因:
对于传统的编码方式,问题的要求可能过于精细,问题可能并不复杂,但是去找不到不那么脆弱的方法。
问题没有任何容易理解的算法去解决。
要解决的问题是一个复杂问题,没有传统的方法,或者问题完全无法理解。
逻辑经常改变
逻辑本身可能是简单的(但是也不是一定会简单),但是规则经常改变,在许多组种种,软件的发布期间隔很久,而规则能够帮助在期望的时间内提供所需要的灵活性。
领域专家(或者是业务分析师)很容易可以找到,但是他们却不是技术人员。
非技术的领域专家通常对于业务逻辑有非常丰富的知识,他们通常不是关注技术而是却非常有逻辑性,规则能够提供让领域专家用他们自己的语言表达逻辑。当然他们仍然不得不思考,精密而且逻辑性的思考。(许多在非技术职位上的人并不擅长这样的思考,所以要小心,当用规则编码业务知识,还还会经常像目前业务规则一样碰见缺陷)
当然,如果,你的项目组对于规则完全是没经验的。在熟悉中的开支也必须要考虑到。这并不是一项简单的技术,但是我们试图是它更简单。
典型的,在现代的OO应用中,你可以用一个规则引擎来容纳业务逻辑的关键部分()-特别是,也就是完全一团糟的部分。这和OO的把逻辑封装到对象中的概念是相反的。这并不是说你你要完全抛弃OO概念,相反的,在任何实际的应用中,业务规则都只是应用的一部分。如果你注意到你的代码中有大量的"if""else""switch"和其他凌乱的逻辑,而且为之发愁(要么因为你错了,或者逻辑改变了,你讲不停的返回来修改)-那么就考虑用规则。如果你正面对困难的问题,而且没有算法或模式去解决,也考虑规则。
规则能够嵌入在你的应用中,或者作为一个服务。通常规则作为有状态的组件会工作的最好,因此,通常是集成在应用中,然而,把规则作为无状态的可重用的服务,也有成功的例子。
在你的组织中,重要的是要考虑一下你在使用的系统中可能或者不得不更新规则的过程。(这个过程可选的,但是不同的组织有不同的需求,而且通常不受应用提供者/项目开发者的控制)
1.2.3什么时候不使用规则引擎
引用Drools邮件列表中的话(Dave Hamu):在我来看来在使用的规则引擎的兴奋中,人们忘记 规则引擎仅仅是复杂应用或解决方案的一个部分。实际上规则引擎并不是打算去解决工作流或者过程的执行,工作流引擎或者过程管理工具也没有设计的要使用规则。使用对工作合适的工具。当然,紧急中一把钳子也能作为榔头使用,但是那并不是设计它的目的。
规则引擎是动态的(动态是从规则能存储,管理,更新上说的),它们通常能看做是配置软件这个问题的解决办法。(most IT departments seem to exist for the purpose of preventing software being rolled out),如果这是你使用规则引擎的原因,要清楚的知道规则引擎在你能够写出声明式的规则时才能提供最佳的工作效果。可选择的,你也可以考虑数据驱动的设计(查找表),或者脚本/过程引擎,其中脚本可以由数据库管理,能够动态的更新。
1.2.4 脚本或者过程引擎
希望上面的章节已经解释了什么时候你可能会用规则引擎。
可选的,基于脚本的引擎也能为不确定的改变提供动态性(有很多解办法)。
像jBPM过程引擎(也能工作流)能让你图形化(或者程序化)的描述一个过程中的步骤-这些步骤也能涉及到决策点,决策点中本身也是一个简单的规则。过程引擎和规则能够很好的一起工作,所以它们并不是非此即彼的关系。
规则引擎中要注意的一个关键是,一些规则引擎实际上是脚本引擎。脚本引擎的不利是你的应用紧紧的和脚本结合在一起,这样可能会给未来的维护造成困难,它们也会随时间变的更复杂。有利的它们能快速的实现,然后你很快的得到结果。
很多人在过去也成功的实现了数据驱动的系统(其中,有控制表来存储能改变你应用行为的元数据),当控制有限时,它们工作的很好。然而,如果需要很多的控制时,这种方法就不行了。或者它会因为不灵活是你的应用不能改变。
1.2.5 紧耦合和松耦合

毫无疑问,在系统设计中你已经听说过紧耦合和松耦合。一般的,在设计上,由于能够增进灵活性,人们认为松耦合或者弱耦合是更好的。对规则也一样,你可能有紧耦合或者松耦合的规则。紧耦合意味着一个规则被触发会清楚的导致另一个规则的触发,换句话,存在清楚的逻辑链。如果你的规则都是紧耦合的,可能的情况就是将会变的不灵活。或者更严重的,可能是过度使用规则引擎了(因为,如果逻辑是很清楚的规则链,那么可以写入代码中)。并不是说紧耦合或者松耦合必定是坏的,当考虑到一个规则引擎的时候,它是你要始终考虑住的一点,同样也是在你如何捕获规则的时候。松耦合将产生的系统中规则能够改变,去处,添加而不用考虑其他不相关的规则。

1.3 知识表达
1.3.1 产生式
一个产生式归,或者规则,在Drools中是一个包括两部分的结构,有左部(left hand side LHS )和右部(right hand side RHS)。附加的,一个规则可能有下面属性:
      salience
      agenda-group
      auto-focus
      activation-group
      no-loop
      duration
rule “”   
       
    when       
           
    then       
       
end
规则的LHS包括条件元素(conditional elements CE)和Columns,可以编码命题和一阶逻辑。
column用来指出一个事实(Fact)上的域限制。
Drools当前支持下面CE:
'and'  'or' 'not' 'exists'
'forall' and 'accumulat' 很快就会添加进来。
有下面这些域限制:
  
      Literal Constraint
      Bound Variable Constraint
      Return Value
      Predicate
语言指南那章会提供更详细的信息。
当在工作存储中声明或修改一个事实时,它会匹配LHS条件,当所有的条件都符合,并且值为‘真’规则加上那些符合的事实就会被激活。当一个规则被激活后,它会放入议程中,由议程决定它的执行当RHS执行,LHS和RHS的效果就类似于:
if ( ) {
   
}
然而,'if'这个词是过程式的,它只一个可能执行流(如if this.... else if.... else .....)的一部分。规则用‘when’语义上更加清楚的表示当且仅当LHS匹配的时候,规则激活。
用package关键字规则和一个命名空间关联,别的规则引擎能够把这个包叫做规则集。一个包声明import,全局变量,函数和规则
package com.sample
import java.util.List
import com.sample.Cheese
global List cheeses
function void exampleFunction(Cheese cheese) {
    System.out.println( cheese );
}
rule “A Cheesey Rule”
    when
        cheese : Cheese( type == "stilton" )
    then
        exampleFunction( cheese );
        cheeses.add( cheese );
end
下面这个例子表明一个有单个Column的LHS,这个Column有一个用在Chess事实中的Literal Field Constraint。
rule "Cheddar Cheese"
    when
        Cheese( type == "cheddar" )
    then
        System.out.println( "cheddar" );
end
这个例子效果类似于:
public void cheddarCheese(Cheese cheese) {
    if ( cheese.getType().equals("cheddar") {
        System.out.println( "cheddar" );
    }
}
规则完全的分离了逻辑和数据。规则不能直接的调用,它们并不是方法或函数,规则由工作存储中的数据的改变而触发。
1.3.2 一阶逻辑
规则用一阶逻辑或叫谓词逻辑(命题逻辑的扩展)书写,Emil Leon Post 是第一个开发基于推理的系统,用符合来表达逻辑,结论是,他能证明,任何逻辑系统(包括数学)能用这样的一个系统来表达。
一个命题是有真假值的陈述句。如果仅从这句子本身就能确定真值,那么它是一个‘closed statement’,在程序中,这就等于是不参考任何变量的表达式。
10==2*5
需要计算一个或多个变量的表达式,事实,是‘open statement’,也就是,除非变量被计算出来,否则我们不能确定陈述句的真假值。
Person.sex-"male"
如果我们结论动作是返回符合的事实,用SQL
select * from People where People.sex == "male"

对任何代表我们事实的行,我们推断出这些事实是male peopele。下面这个图可显示,用推理引擎的观点,sql语句和people表是如何表示的。

Drools第一章 <wbr>1.2 <wbr>1.3所以,在java中,我们能看见简单的命题,它们有variable' 'operator' 'value' 这样的形式,'value'通常是字面量(literal value)-这样就是一个可以看做是域限制的s命题。更甚,这个命题可以用‘与’‘或’连接。例如下面的代码采用'&&' '||'形式的逻辑连接。

person.getEyeColor().equals("blue") || person.getEyeColor().equals("green")
它也能用析取条件元素连接,会产生两条规则
Person( eyeColour == "blue" ) || Person( eyeColor == "green" )
也可以析取的域限制连接,尽管现在在Drools3.0中还不支持。这样不会产生多条规则。
Person( eyeColour == "blue"||"green" )
然而命题逻辑并不是图灵完全的,这样,它就会限制你所能表达的问题,因为它不能表达数据的结构。一阶逻辑通过两个量词概念扩展了命题逻辑,允许表达式定义结构。(存在量词,全称量词)。全称量词允许你检查对所有的某些事情是正确的。但是当前的Drools3.0中还不支持。存在量词检查存在某些事情。也就说至少一次。它通过‘not’和‘exists’条件元素来支持。
设想我们有两个类-student 和Module。Module代表学生这个学期参加的每一个课程,通过List表示。在学期结束。每个Module有一个成绩。如果学生有一个成绩低于40分,那么这个学期就不及格。-存在量词能用在这样的情况中。
public class Student {
    private String name;
    private List modules;
    ...
}
public Class Module {
    private String name;
    private String studentName;
    private int score;
Java是图灵完全的, 你能写代码循环数据结构来检查存在性。
List failedStudents = new ArrayList();
for ( Iterator studentIter = students.iterator(); studentIter.hasNext() {
    Student student = ( Student ) studentIter.next();
    for ( Iterator it = student.getModules.iterator(); it.hasNext(); ) {
        Module module = ( Module ) it.next();
        if ( module.getScore() < 40  ) {
            failedStudents.add( student ) ;
            break;
        }
    }
}

早期的SQL实现不是图灵完全的,因为它们并没有提供量词来计算数据的结构。然而现在的SQL引擎允许嵌套SQL,能够组合关键词如‘exists’或‘in’:下面的查询返回不及格的student集合:
select
    *
from
    Students s
where exists ( 
    select
        *
    from
        Modules m
    where
        m.student_name = s.name and
        m.score < 40
)
rule
    when
        exists( $student : Student() && Module( student == $student, score < 40 ) )
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章