最近刚刚接触JAVA的规则引擎,一般的系统而言,业务不是非常复杂,而且变化少,因此很少采用什么规则引擎,最近接触了一个规则引擎的系统,是使用BlazeSoft公司的Blaze来实现的,自己对它正在了解中,把具体的实现相关的知识,写下来,以待进一步的整理。
本系列文章主要先人云亦云地介绍一下规则引擎的背景知识(本人了解规则引擎不多),接着介绍JSR94的 API和具体的实现,以及blaze自己提供的java api的简单介绍和实现,然后介绍一下BlazeSoft公司的blaze的搭建、开发和部署,以及在java环境中的集成,简单介绍一下Blaze使用 的规则语言,srl的语法。
规则引擎的简介
规则引擎
规则引擎是推理引擎的一种,它起源于基于规则的专家系统。规则引擎好像不是新鲜的话题了,但在java应用中,好像以前讨论得不多,不久热起来的。
规则引擎也就是基于规则的专家系统中的推理引擎发展而来。下面简要介绍一下基于规则的专家系统。
引用一段相关文章的介绍 :
RBES的推理(规则)引擎
和人类的思维相对应,规则引擎存在两者推理方式:演绎法(Forward-Chaining)和归纳法(Backward-Chaining)。演绎法从 一个初始的事实出发,不断地应用规则得出结论(或执行指定的动作)。而归纳法则是从假设出发,不断地寻找符合假设的事实。
Rete算法是目前效率最高的一个Forward-Chaining推理算法,Drools项目是Rete算法的一个面向对象的Java实现。
规则引擎的推理步骤如下:
1. 将初始数据(fact)输入Working Memory。
2. 使用Pattern Matcher比较规则(rule)和数据(fact)。
3. 如果执行规则存在冲突(conflict),即同时激活了多个规则,将冲突的规则放入冲突集合。
4. 解决冲突,将激活的规则按顺序放入Agenda。
5. 使用规则引擎执行Agenda中的规则。重复步骤2至5,直到执行完毕所有Agenda中的规则。
具体请参考其他相关文章的介绍。
规则引擎是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据规则做出业务决策。
“Java规则引擎将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。Java规则引擎接受数据输入,解释业务规则,并根据规则 作出业务决策。从这个意义上来说,它是软件方法学在”关注点分离”上的一个重要的进展。”,有人说,soa的发展成熟,将给规则引擎提供良好的切入。
但是究竟什么是规则引擎,在业界中还没有统一的说法,至今仍然是个争议性的问题,因此也就缺少标准,如今比较流行的,作为规则引擎实现标准化的JSR 94(Java规则引擎API)也对此几乎没有任何定义,因此,暂且不深究吧。
为什么要使用规则引擎,它所适合的场所?
在保险业和金融服务业都广泛地使用了基于规则的编程技术,当需要在大量的数据上应用复杂的规则时,规则引擎技术特别有用。
以前参与过一个系统,是一个物流的调度系统,当时遇到一个问题,就是在实施的最后一个月中,客户的业务产生了多次变化,而且一直都有可能变化 。该系统业务比较复杂,变化大,这是在需求开发中是没有料到的,客户他们也一样,他们也不能预测以后的业务会发生怎样的变化。后来经过打了一系列的补丁才 解决了问题,有些不可解决的问题,还是最后通过双方的让步,最终通过妥协解决的。后来想想,应该在需求研发中加大比重,挖掘隐性需求,另外应该利用工作流 引擎结合简单的规则引擎,应该可以相应的降低或者避免后来出现的问题,以适应客户的不断变化的业务发展。
我们其实在今天一直都在讨论在什么时候以及什么场所中,该使用规则引擎,这个疑问对于大多数人都存在,就像连规则引擎是什么,如何使用,这两个问题都没有 统一的答案一样,一切好像都存在很大的争议性,我们暂且不深究吧。像以前作的系统,有人提倡使用什么什么引擎,后来觉得我们水平不够,使用的学习成本也不 低,不是很复杂的系统的业务逻辑,直接嵌入coding一样没问题,并且一些常变的规则,我们把它做成可配置(当然如果变化的规则变得越来越庞大的话,那 是灾难性的)。总之还是可以满足需求。 看过相关的介绍,一般是指两方面的需求:
一、业务模式不成熟,跟着业务的发展,和行业的成熟,业务规则或者模式会经常变换,另外就是根据市场的需求,业务规则也经常变化。我们适用这些规则的变化,可以让业务人员直接变更这些系统中的规则,不需要开发人员的参与。
二、我们开发的系统,很多业务规则在需求研发阶段并不明朗,规则的变化可能一直贯穿到设计和编码,甚至在维护和运营之中。因此,我们需要一个相关的框架来 对这些业务规则,进行统一的管理。像EJB和Spring只能在高端实现商务逻辑构建,但并不能提供具体的code的管理。用在配置性,可读性和重用性方 面,带给我们极大利益的框架,来代替那些嵌入到系统代码中的if-else等逻辑(这些逻辑往往可读性差),看过一篇文章,是做这方面探讨的,有一些启 发,请看http://lizwjiang.blog.hexun.com/3475785_d.html。
其实在实践中,带来的利益是上述两者兼而有之的,就像一般的规则引擎语言,都是比较简单明了的语言,像balze公司的STRUTURED RULE LANGUAGE,它追求的目标是,它的语法“as English-like as possible”,是比较容易懂,也易学,他的维护界面,也停供可视化的操作界面,因此在管理这些规则,某些简单的规则,业务人员是可以操作的,其实, 在某些系统中,很多具体的业务变化,改变的都是这些规则。另外,它作为一个规则代码统一管理的框架,或者叫它嵌入式的组件,对这些规则的统一管理是非常方 便的,而且不用重启应用系统。
当然,至于说完全不用开发人员的参与,让业务人员去维护规则,就今天的发展现状而言,有点痴人说梦矣。
总的来说,“复杂企业级项目的开发以及其中随外部条件不断变化的业务规则(business logic),迫切需要分离商业决策者的商业决策逻辑和应用开发者的技术决策,并把这些商业决策放在中心数据库或其他统一的地方,让它们能在运行时(即商 务时间)可以动态地管理和修改从而提供软件系统的柔性和适应性。规则引擎正是应用于上述动态环境中的一种解决方法。”
下面转述一下相关的产品的介绍
目前主流的规则引擎组件多是基于Java和C++程序语言环境,已经有多种Java规则引擎商业产品与开源项目的实现,其中有的已经支持JSR94,有的正朝这个方向做出努力,列出如下:
Java规则引擎商业产品有:
l. ILOG公司的JRules(见 http://www.ilog.com/produts/jrules/)
2. BlazeSoft公司的Blaze(见 http://www.fairisaac.com)
3. Rules4J
4. Java Expert System Shell (JESS)(见http://herzberg.ca.sandia.com/jess)
Jess不是开源项目,它可以免费用于学术研究,但用于商业用途则要收费
开源项目的实现包括:
l. Drools项目(见 http://drools.org/)
Drools规则引擎应用Rete算法的改进形式Rete-II算法。从内部机制上讲,它使用了和Forgy的算法相同的概念和方法,但是增加了可与面向对象语言无缝连接的节点类型。
最近Drools被纳入JBoss门下,更名为JBoss Rules,成为了JBoss应用服务器的规则引擎。
有一篇入门的介绍文章,见:http://www.blogjava.net/guangnian0412/archive/2006/06/04/50251.aspx
2. JLisa项目(见 http://jlisa.sourceforge.net/)
JLisa是用来构建业务规则的强大框架,它有着扩展了LISP优秀特色的优点,比Clips还要强大.这些特色对于多范例软件的开发是至关重要的。它实现了JSR94 Rule Engine API。
3. OFBiz Rule Engine(不支持JSR 94)
4. Mandarax(见 http://mandarax.sourceforge.net/)
Mandarax是一个规则引擎的纯Java实现。基于反向推理(归纳法)。能够较容易地实现多个数据源的集成。例如,数据库记录能方便地集成为事实集 (facts sets),reflection用来集成对象模型中的功能。支持XML标准(RuleML 0.8)。它提供了一个兼容J2EE的使用反向链接的接口引擎。目前不支持JSR 94。
还有其他,在我们社区也有相关的介绍,例如:http://www.javaeye.com/topic/7803?page=7
5、OFBiz Rule Engine - 支持归纳法(Backward chaining).最初代码基于Steven John Metsker的”Building Parsers in Java”,不支持JSR 94
其它的开源项目实现有诸如Algernon, TyRuBa, JTP, JEOPS, InfoSapient, RDFExpert, Jena 2, Euler, Pellet OWL Reasoner, Prova, OpenRules, SweetRules, JShop2等等。
目前规则引擎比较流行的算法是都来自于Dr. Charles Forgy在1979年提出的RETE算法及其变体,Rete算法是目前效率最高的一个Forward-Chaining推理算法。详情请见 CIS587:The RETE Algorithm,The Rete Algorithm,RETE演算法,《专家系统原理与编程》中第11章等。
规则语言
是规则引擎应用程序的重要组成部分,所有的业务规则都必须用某种语言定义并且存储于规则执行集中,从而规则引擎可以装载和处理他们。
Java Specification Request (JSR) 94没有为任何类型的业务规则(如,基于XML的、基于统一数据的或基于对象模型的)指定描述语言。由于没有关于规则如何定义的公用规范,市场上大多数流 行的规则引擎都有其自己的规则语言,目前便有许多种规则语言正在应用。流行的规则语言:
STRUTURED RULE LANGUAGE(srl) http://www.fairisaac.com
Rule Markup language (RuleML) http://www.ruleml.org/
Simple Rule Markup Language (SRML) http://xml.coverpages.org/srml.html
Business Rules Markup Language (BRML) http://xml.coverpages.org/brml.html
SWRL: A Semantic Web Rule Language Combining OWL and RuleML http://www.daml.org/2003/11/swrl/
对于规则语法错误可以靠IDE工具来识别,当然,一般的IDE还没有Eclips和JBuilder等 IDE那么方便,JBoss已经有提供Eclipse plugin了。如果要在上述的规则框架中移植这些规则的具体实现,变换规则定义,一般要使用XSLT转换器。当然公用规则语言的缺乏将阻碍不同规则引擎 之间的互操作性,业界现在比较流行的公用操作语言都仍然没有达到各家提供商的一致认可,因此,公用标准的路还很长。
上面说到,目前在市场上留下多种规则引擎的产品,同样有多种的规则引擎语言,存在兼容性的问题。因此,我们 必须提供一个统一的,标准的接口,来实现规则引擎的具体实现与业务应用系统之间的解耦,就像JDBC能够适应多种数据库一样,JSR 94也就顺势而生。当然,由于在语言级的标准路还很长,因此JSR 94只是在java中接口级别的标准。它的出现可以避免在更换实现产品时,必须重写应用程序逻辑和API调用的噩梦。JSR 94的官方网站为:http://jcp.org/en/procedures/jcp2
SR94 的规则引擎API介绍
我们先来看看包内主要的类,如图jsr94.bmp。
我们可以看到,包主要有javax.rules.admin和javax.rules两个目录,前一个目录,顾名思义,就是规则管理API(the rules administration API),后者是其他用途的API,我们称之为运行时API(the Runtime client API)。
规则管理API,我们从上图可以看到主要包括以下几个类:
RuleExecutionSetProvider类:
里面主要重载三个方法createRuleExecutionSet,从名称中可以看出,这个方法负责创建规则执行集。
LocalRuleExecutionSetProvider类:
与之对应的是 RuleExecutionSetProvider类,一个是远程的,一个是本地的(Local)。
规则执行集可以从如XML streams, input streams等来源中创建。在J2EE环境中,Java规则引擎的管理活动是应用服务器的一部分。因此一般规则库跟服务器不在同一台机器上,RuleExecutionSetProvider类可以从远程的经过汇集和系列化的数据来源中获取。
但一般情况而言,使用远程规则引擎或远程规则数据来源的情况并不多见,RuleExecutionSetProvider创建规则执行集会耗费较大的网络开销,所以一般使用的都是LocalRuleExecutionSetProvider类。
RuleAdministrator类:
四个方法:
java 代码
前面两个方法是注册执行集的,第一个参数是URI,作为唯一标识。后面两个是获取远程和本地的RuleExecutionSetProvider。
javax.rules.admin.Rule类
RuleExecutionSet类
这个类就是封装了规则执行集,实例由RuleExecutionSetProvider的createRuleExecutionSet方法创建。
运行时API中比较常用的类有:
RuleServiceProviderManager类:这个类负责注册RuleServiceProvider和获取注册的 RuleServiceProvider。分别见方法registerRuleServiceProvider(String, Class)/registerRuleServiceProvider(String, Class, ClassLoader)和getRuleServiceProvider(String)
注册和获取的方法,第一个参数都是RuleServiceProvider的唯一标识。
RuleServiceProvider类:主要的两个方法getRuleAdministrator()和getRuleRuntime(),负责获取RuleRuntime和RuleRuntime的实例。
RuleRuntime类:提供一个createRuleSession(String, Map, int)方法创建rule执行会话。第一个参数就是上面注册RuleServiceProvider和RuleExecutionSet时候的uri,唯 一标识。拥有一个唯一标识的RuleServiceProvider和RuleExecutionSet,可以创建多个rule session。第三个参数是一个整数,它用于标示创建有状态的还是无状态的session。
StatefulRuleSession类和StatelessRuleSession类,这两个类都继承了RuleSession类,规则执行会 话主要维护规则的执行调用。无状态会话的工作方式就像一个无状态会话bean.客户可以发送单个输入对象或一列对象来获得输出对象.当客户需要一个与规则 引擎间的专用会话时,有状态会话就很有用.输入的对象通过addObject() 方法可以加入到会话当中.同一个会话当中可以加入多个对象.对话中已有对象可以通过使用updateObject()方法得到更新。只要客户与规则引擎间 的会话依然存在,会话中的对象就不会丢失。
RuleExecutionSetMetadata类:接口提供给客户让其查找规则执行集的元数据(metadata)。元数据通过规则会话接口(RuleSession Interface)提供给用户。
总之,规则管理API主要提供装载规则以及与规则对应的动作(执行集 execution sets)以及实例化规则引擎以及对执行集进行维护。规则可以从外部资源中装载,比如说URI,Input streams, XML streams和readers等等。同时,规则引擎API提供了这样一个机制,就是访问RuleServiceProvider和 RuleExecutionSet的实例,两者都必须先在服务器上注册,然后才能根据注册中使用的uri来获取。这样,有助于对客户访问运行规则进行控制 管理,它通过在执行集上定义许可权使得未经授权的用户无法访问受控规则。而运行时API是提供了一个对规则执行集访问的机制,类似于JDBC的访问方法。 类RuleServiceProvider提供了对具体规则引擎实现的运行时和管理API的访问,将其规则引擎实现提供给客户,并获得 RuleServiceProvider唯一标识规则引擎的URI。
我们且看,一个规则实现的注册,然后到客户访问和执行规则的步骤。
第一步:先实例化ruleServiceProvider,这个ruleServiceProvider,就是提供具体的规则引擎实现,不同的规则 引擎提供商有不同的provider。它的格式标准用法一般是例 如:com.mycompany.myrulesengine.rules.RuleServiceProvider,我使用blaze,因此代码片断如下:
java 代码
第二步:注册ruleServiceProvider。上面说到,使用RuleServiceProviderManager,如下:
java 代码
第三步:获取刚才注册的ruleServiceProvider实例(上面说过,要使用ruleServiceProvider的实例,必须先注册)
java 代码
第四步:获取RuleAdministrator的实例,因为注册和管理规则执行集,都是在RuleAdministrator中进行的。
java 代码
第五步:在Administrator实例中获取rule execution set provider
java 代码
第六步:通过rule execution set provider的实例创建RuleExecutionSet
java 代码
第七步:注册RuleExecutionSet。
java 代码
下面是创建会话,然后执行规则集。
第八步:获取RuleRuntime 的实例,然后根据RuleRuntime 的实例创建执行会话。
java 代码
最后:执行规则集,释放会话资源。
java 代码