【java规则引擎】之规则引擎解释

转载:http://www.open-open.com/lib/view/open1417528754230.html

现实生活中,规则无处不在。法律、法规和各种制度均是;对于企业级应用来说,在IT技术领域,很多地方也应用了规则,比如路由表,防火墙策略,乃至角色权限控制(RBAC),或者Web框架中的URL匹配。不管是那种规则,都规定了一组确定的条件和此条件所产生的结果。

举一个例子:

IF

汽车是红色
车是运动型的
驾驶员是男性
驾驶员在16-25岁之间
THEN

保险费用增加20%

从这个例子可以看出:

每条规则都是一组条件决定的一系列结果
一条规则可能与其他规则共同决定最终结果。比如例子中的规则只产生了增量,还需要与确定基数的规则共同作用才能决定最终的费率
可能存在条件互相交叉的规则,此时有必要规定规则的优先级
规则作为一种知识,其典型运用就是通过实际情况,根据给定的一组规则,得出结论。这个结论可能是某种静态的结果,也可能是需要进行的一组操作。这种 规则的运用过程叫做推理。如果由程序来处理推理过程,那么这个程序就叫做推理机/推理引擎。推理引擎根据知识表示的不同采取的控制策略也是不同的,常见的 类型包括基于神经网络、基于案例和基于规则的推理机。其中,基于规则的推理机易于理解、易于获取、易于管理,被广泛采用。这种推理引擎被称为“规则引 擎”。

规则引擎起源于基于规则的专家系统(专家系统CLIPS: 源于1984年NASA的人工智能项目,现已开源,由C编写。),而基于规则的专家系统又是专家系统的其中一个分支。专家系统属于人工智能的范畴,它模仿 人类的推理方式,使用试探性的方法进行推理,并使用人类能理解的术语解释和证明它的推理结论。基于规则的专家系统(RBES)包括三部分:Rule Base(knowledge base)、Working Memory(fact base)和Inference Engine。它们的结构如下系统所示:

推理引擎(Inference Engine)包括三部分:模式匹配器(Pattern Matcher)、议程(Agenda)和执行引擎(Execution Engine)。推理引擎通过决定哪些规则满足事实或目标,并授予规则优先级,满足事实或目标的规则被加入议程。

模式匹配器决定选择执行哪个规则,何时执行规则;
议程管理模式匹配器挑选出来的规则的执行次序;
执行引擎负责执行规则和其他动作。
和人类的思维相对应,规则引擎中也存在两种推理方式:正向推理(Forward-Chaining)和反向推理(Backward-Chaining)。

正向推理也叫演绎法,由事实驱动,从 一个初始的事实出发,不断地应用规则得出结论。首先在候选队列中选择一条规则作为启用规则进行推理,记录其结论作为下一步推理时的证据。如此重复这个过程,直到再无可用规则可被选用或者求得了所要求的解为止。
反向推理也叫归纳法,由目标驱动,首先提出某个假设,然后寻找支持该假设的证据,若所需的证据都能找到,说明原假设是正确的;若无论如何都找不到所需要的证据,则说明原假设不成立,此时需要另做新的假设。
将事实与规则进行匹配的算法。常见的模式匹配算法有RETE,LFA,TREAI,LEAPS。Rete算法是目前效率最高的一个演绎法推理算法,许多规则引擎都是基于Rete算法来进行推理计算的。

推理引擎的推理步骤如下:模式匹配、冲突消解、执行引擎。

将初始数据(fact)输入 Working Memory 。
使用 Pattern Matcher 比较规则库(rule base)中的规则(rule)和数据(fact)。
如果执行规则存在冲突(conflict),即同时激活了多个规则,将冲突的规则放入冲突集合。
解决冲突,将激活的规则按顺序放入Agenda。
使用执行引擎执行Agenda中的规则。重复步骤2至5,直到执行完毕所有Agenda中的规则。
规则引擎的作用:

规则外部化,即有利于规则知识的复用,也可避免改变规则时带来的代码变更问题
由规则引擎使用某种算法进行推理过程,不需要编写复杂晦涩的逻辑判断代码
开发人员的不需要过多关注逻辑判断,可以专注于逻辑处理

RETE算法

Rete在拉丁语中是“net”,有网络的意思。Rete算法由Carnegie Mellon University的Dr Charles L. Forgy设计发明,是一个用来实现产生式规则系统(production/inference)的高效模式匹配算法。

RETE算法可以分为两部分:规则编译(rule compilation)和运行时执行(runtime execution)。

规则编译===>是指根据规则集生成推理网络的过程。

运行时执行===>指将数据送入推理网络进行筛选的过程。

相关概念:

事实(Fact):对象之间及对象属性之间的关系
规则(rule):是由条件和结论构成的推理语句,一般表示为if…Then。一个规则的if部分称为LHS(left-hand-side),then部分称为RHS(right hand side)。
模式(module):就是指IF语句的条件。这里IF条件可能是有几个更小的条件组成的大条件。模式就是指的不能在继续分割下去的最小的原子条件。
RETE推理网络的生成过程:从规则集{规则1,规则2……..}中拿出一条来,根据一定算法,变成RETE推理网络的节点。不断循环将所有规则都处理完,RETE推理网络就生成了。RETE网络主要分为两个部分,alpha网络和beta网络。如下图所示。

alpha网络:过滤working memory,找出符合规则中每一个模式的集合,生成alpha memory(满足该模式的集合)。有两种类型的节点,过滤type的节点和其他条件过滤的节点(我觉得这两种是依照需要设定的,也并不一定需要两种节点)。
Beta网络:有两种类型的节点Beta Memory和Join Node。前者主要存储Join完成后的集合。后者包含两个输入口,分别输入需要匹配的两个集合,由Join节点做合并工作传输给下一个节点。
在一个产生式系统中,主要流程可以分为以下步骤:

Match:找出符合LHS部分的working memory集合
Confilict resolution:选出一个条件被满足的规则
Act:执行RHS的内容
返回1
RETE算法主要改进Match的处理过程,通过构建一个网络进行匹配。

具体过程如下:

创建root节点(根节点),推理网络的入口。
拿到规则1,从规则1中取出模式1(前面说了,模式就是最小的原子条件,所以规则模式的关系是1:n)。
a)   检查模式1中的参数类型,如果是新类型,添加一个类型节点。

b)   检查模式1对应的Alpha节点是否存在,如果存在记录下节点的位置;如果没有,将模式1作为一个Alpha节点加入到网络中。同时根据Alpha节点建立Alpah内存表。

c)   重复b,直到处理完所有模式。

d)   组合Beta节点:Beta(2)左输入节点为Alpha(1),右输入节点为Alpha(2);Beta(i)左输入节点是Beta(i-1),右输入节点为Alpha(i),并将两个父节点的内存表内联成为自己的内存表

e)   重复d,直到所有Beta节点处理完毕

f)   将动作Then部分封装成最后节点做为Beta(n)

重复2,直到所有规则处理完毕
下面是一个从网上找得例子:

规则P1:

LHS:

C1:(年纪:研2)
C2:(性别:男)
C3:(身材:较瘦)
C4:(身高:大于175cm)
RHS:

标点符

Rete算法优于传统的模式匹配算法的特点

状态保存。事实集合中的每次变化,其匹配后的状态都被保存再alpha和beta节点中。在下一次事实集合发生变化时,绝大多数的结果都不需要变 化,rete算法通过保存操作过程中的状态,避免了大量的重复计算。Rete算法主要是为那些事实集合变化不大的系统设计的,当每次事实集合的变化非常剧 烈时,rete的状态保存算法效果并不理想。
节点共享

Drools中用到的RETE算法

编译算法描述了规则如何在Production Memory中产生一个有效的辨别网络。用一个非技术性的词来说,一个辨别网络就是用来过滤数据。方法是通过数据在网络中的传播来过滤数据。在顶端节点将 会有很多匹配的数据。当我们顺着网络向下走,匹配的数据将会越来越少。在网络的最底部是终端节点(terminal nodes)。在Dr Forgy的1982年的论文中,他描述了4种基本节点:root, 1-input, 2-input and terminal。

下图是Drools中的RETE节点类型:

根节点(RootNode)是所有的对象进入网络的入口。然后,从根节点立即进入到ObjectTypeNode。ObjectTypeNode的 作用是使引擎只做它需要做的事情。例如,我们有两个对象集:Account和Order。如果规则引擎需要对每个对象都进行一个周期的评估,那会浪费很多 的时间。为了提高效率,引擎将只让匹配object type的对象通过到达节点。通过这种方法,如果一个应用assert一个新的account,它不会将Order对象传递到节点中。很多现代RETE实 现都有专门的ObjectTypeNode。在一些情况下,ObjectTypeNode被用散列法进一步优化。

ObjectTypeNode能够传播到AlphaNodes,LeftInputAdapterNodes和BetaNodes。

1-input节点通常被称为AlphaNode。AlphaNodes被用来评估字面条件(literal conditions)。虽然,1982年的论文只提到了相等条件(指的字面上相等),很多RETE实现支持其他的操作。例如,Account.name == “Mr Trout”是一个字面条件。当一条规则对于一种object type有多条的字面条件,这些字面条件将被链接在一起。这是说,如果一个应用assert一个account对象,在它能到达下一个 AlphaNode 之前,它必须先满足第一个字面条件。在Dr. Forgy的论文中,他用IntraElement conditions来表述。下面的图说明了Cheese的AlphaNode组合(name == “cheddar”,strength == “strong”):

Drools通过散列法优化了从ObjectTypeNode到AlphaNode的传播。每次一个AlphaNode被加到一个 ObjectTypeNode的时候,就以字面值(literal value)作为key,以AlphaNode作为value加入HashMap。当一个新的实例进入ObjectTypeNode的时候,不用传递到每 一个AlphaNode,它可以直接从HashMap中获得正确的AlphaNode,避免了不必要的字面检查。

2-input节点通常被称为BetaNode。Drools中有两种BetaNode:JoinNode和NotNode。BetaNodes被用来对2个对象进行对比。这两个对象可以是同种类型,也可以是不同类型。

我们约定BetaNodes的2个输入称为左边(left)和右边(right)。一个BetaNode的左边输入通常是a list of objects。在Drools中,这是一个数组。右边输入是a single object。两个NotNode可以完成‘exists’检查。Drools通过将索引应用在BetaNodes上扩展了RETE算法。下图展示了一个 JoinNode的使用:

注意到图中的左边输入用到了一个LeftInputAdapterNode,这个节点的作用是将一个single Object转化为一个单对象数组(single Object Tuple),传播到JoinNode节点。因为我们上面提到过左边输入通常是a list of objects。

Terminal nodes被用来表明一条规则已经匹配了它的所有条件(conditions)。 在这点,我们说这条规则有了一个完全匹配(full match)。在一些情况下,一条带有“或”条件的规则可以有超过一个的terminal node。

Drools通过节点的共享来提高规则引擎的性能。因为很多的规则可能存在部分相同的模式,节点的共享允许我们对内存中的节点数量进行压缩,以提供遍历节点的过程。下面的两个规则就共享了部分节点:

 1 rule
 2     when
 3         Cheese( $chedddar : name  ==  " cheddar "  )
 4         $person : Person( favouriteCheese  ==  $cheddar )
 5     then
 6         System.out.println( $person.getName()  +   "  likes cheddar "  );
 7 end
 8
 9 rule
10     when
11         Cheese( $chedddar : name  ==   " cheddar "  )
12         $person : Person( favouriteCheese  !=  $cheddar )
13     then
14         System.out.println( $person.getName()  +   "  does likes cheddar "  );
15 end

从图上可以看到,编译后的RETE网络中,AlphaNode是共享的,而BetaNode不是共享的。上面说的相等和不相等就体现在BetaNode的不同。然后这两条规则有各自的Terminal Node。

RETE算法的第二个部分是运行时(runtime)。当一个应用assert一个对象,引擎将数据传递到root
node。从那里,它进入ObjectTypeNode并沿着网络向下传播。当数据匹配一个节点的条件,节点就将它记录到相应的内存中。这样做的原因有以
 
下几点:主要的原因是可以带来更快的性能。虽然记住完全或部分匹配的对象需要内存,它提供了速度和可伸缩性的特点。当一条规则的所有条件都满足,这就是完
 
全匹配。而只有部分条件满足,就是部分匹配。(我觉得引擎在每个节点都有其对应的内存来储存满足该节点条件的对象,这就造成了如果一个对象是完全匹配,那
 这个对象就会在每个节点的对应内存中都存有其映象。)

参考链接:

引用地址:http://www.biaodianfu.com/rules-engine.html

时间: 2024-10-13 02:46:32

【java规则引擎】之规则引擎解释的相关文章

Java正则表达式之语法规则

[转]Java正则表达式之语法规则 正则表达式是一种强大而灵活的文本处理工具,使用正则表达式能够以编程的方式,构造复杂的文本模式,并对输入的字符串进行搜索.一旦找到了匹配这些模式的部分,就能够随心所欲地它们进行处理.正则表达式提供了一种完全通用的方式,能够解决各种字符串处理相关的问题:匹配.选择.编辑以及验证. 首先看一下JAVA中正则表达式的完整构造集,也可以参考java.util.regex.Pattern中的API说明. 字符 X 字符X \\ 反斜线字符 \0n 带有八进制值0的字符n(

Java三大主流开源工作流引擎技术分析

Java三大主流开源工作流引擎技术分析 首先,这个评论是我从网上,书中,搜索和整理出来的,也许有技术点上的错误点,也许理解没那么深入.但是我是秉着学习的态度加以评论,学习,希望对大家有用,进入正题! 三大主流工作流引擎:Shark,osworkflow,jbpm! Shark的靠山是Enhydra.Enhydra做过什么呢?多了!从j2ee应用服务器,到o/r mapping工具,到这个工作流引擎等等.为什么Shark的持久层采用DODS来实现?就是因为他们是一家人. Jbpm的靠山是jboss

StyleCop中有一些官方自己写好的检测规则下面就是英文的解释

在StyleCop中有一些官方自己写好的检测规则下面就是英文的解释 文档规则 1.SA1600:ElementsMustBeDocumented元素必须添加注释 2.SA1601: PartialElementsMustBeDocumented   Partial修饰的成员必须添加注释 3.SA1602:EnumerationItemsMustBeDocumented 枚举必须添加注释 4.SA1603: DocumentationMustContainValidXml  注释必须合法(注释中的

重新认识Java包的命名规则

在软件开发这个行当"混了"几年,如果这时再提Java包的命名规则未免有点小儿科了,别急呀:大家看下面这个工程以及里面的代码: 看到这个工程后,想来大家应该"理所当然"地认为"没问题啊",呵呵呵,那么当我们运行程序时会发生什么呢?看下图: 怎么造成的?很简单:Java的包名不能以"java"开头.

Java 8 的 Nashorn 脚本引擎教程

本文为了解所有关于 Nashorn JavaScript 引擎易于理解的代码例子. Nashorn JavaScript 引擎是Java SE 8的一部分,它与其它像Google V8 (它是Google Chrome 和Node.js的引擎)的独立引擎相互竞争. Nashorn 扩展了Java在JVM上运行动态JavaScript脚本的能力. 在接下来的大约15分钟里,您将学习如何在 JVM 上动态运行 JavaScript. 通过一些简短的代码示例演示最近 Nashorn 的语言特性. 学习

Java标识符的命名规则

Java语言中,为各种变量.方法和类等起的名字称为标识符Java标识符的命名规则:应以字母.下划线.美元符开头后跟字母.下划线.美元符或数字Java标识符大小写敏感,长度无限制 1.java中能用作标识符的有:26个英文字母(大.小写),数字,下划线,美元符号$. 但是不能以数字开头. 2.类名首个字母必须大写,多个单词组成的,每个单词首字母都要大写. 3.方法名一般首个字母小写(构造方法例外),多个单词组成方法名,后面单词首字母大写. 4.变量命名规则同方法名名. 注意:不能使用java中的关

java标识符与命名规则

标识符就是给变量.类或方法起的名字.可以用字母.下划线或美元符号开头,区分大小写,没有最大长度限制.(关键字除外) 关键字 访问控制 private protected public             类,方法和变量修饰符 abstract class extends final implements interface native new static strictfp synchronized transient volatile           程序控制 break conti

浏览器内核、排版引擎、js引擎

[定义] 浏览器最重要或者说核心的部分是“Rendering Engine”,可大概译为“渲染引擎”,不过我们一般习惯将之称为“浏览器内核”.负责对网页语法的解释(如标准通用标记语 言下的一个应用HTML.JavaScript)并渲染(显示)网页. 所以,通常所谓的浏览器内核也就是浏览器所采用的渲染引擎,渲染引擎决定了浏览器如何显示网页的内容以及 页面的格式信息.不同的浏览器内核对网页编写语法的解释也有不同,因此同一网页在不同的内核的浏览器里的渲染(显示)效果也可能不同,这也是网页编写者需要在不

图片识别引擎-识图引擎搜集~

图片识别引擎-识图引擎搜集 识图现在搜索结果还是不够理想,有很大的提升空间,下面介绍几个比较专业的图片搜索引擎. 1: https://images.google.com/ http://www.google.com/imghp (旧版:http://similar-images.googlelabs.com) 暂时的替代品:http://203.208.46.200/imghp Google实验室类似图片搜索:输入一个关键词后,例如"bird",返回的页面里面点击某个图片的下面的Si

80 脚本引擎——js脚本引擎

脚本引擎管理工具 java提供了一个脚本引擎管理工具,从这个工具可以获得各种脚本语言的脚本引擎,如js.python等.我们可以通过脚本引擎,来调用已经写好的脚本文件.相当的方便. 我们可以使用:new ScriptEngineManager()获取一个脚本引擎管理工具对象. 然后,可以通过getEngineByName(scriptName)的方式得到我们想要的脚本引擎. //获取脚本引擎管理器 ScriptEngineManager sem = new ScriptEngineManager