drools RETE算法

rete可以被分为两部分:规则编译和运行执行。规则编译是指根据规则集生成推理网络的过程,运行时执行指将数据送入推理网络进行筛选的过程。

基本概念

Rete算法的初衷是:利用规则之间各个域的公用部分减少规则存储,同时保存匹配过程的临时结果以加快匹配速度。为了达到这种效果,算法将规则拆分,其中每个条件单元作为基本单位(节点)连接成一个数据辨别网络,然后将事实(facts)经过网络筛选并传播,最终所有条件都有事实匹配的规则被激活。

网络共有5类节点:root节点、type节点、alpha节点(也称单输入节点)、beta节点(也称双输入节点)、terminal节点等。

根节点

代表整个Rete网络的入口,它可以让所有的事实通过,并传递给ObjectType节点。作为根节点的后继,

类型节点

ObjectType Node就是我们的fact,也就是我们规则所用到的pojo,用于选择事实的类型,将符合本节点类型的事实向后继的alpha节点传播。

alpha节点

alpha节点主要进行同对象类型内属性的约束或常量测试,比如“name==zhang”,“age>15”等等。

一条简单的规则

rule "规则1:账户余额小于100"
  when
    $account:Account(balance<100)
  then
    print("账户余额小于100");
end

规则1对应的rete网络如下:

这里写图片描述

LeftInputAdapterNode节点

这个节点的作用是将一个事实对象转化为一个元组,主要为beta节点提供作用。

beta节点

beta节点主要根据不同对象之间的约束,如“p.name==c.friend”,“p.age>cat.age”等进行连接操作。beta节点又分为join节点、Not节点等。Join节点包括两种输入,左部输入事实列表,称为元组(Tuple),右部输入一个事实对象,对象与元组在Join节点按照类型间约束进行Join操作,将符合的事实加入元组中继续传入下一个beta节点。

在规则1基础上增加条件,形成另外一条规则

rule "规则2:账户余额小于100的姓张的学生卡"
  when
    $account:Account(balance<100,type=Account.Type.学生)
    $customer:Customer(firstName = 'zhang',accounts contains $account)
  then
    print("账户余额小于100的姓张的学生卡");
end

规则2对应的rete网络如下:

这里写图片描述

Terminal节点

Terminal节点是规则的末尾节点,它代表一个规则匹配结束,当事实或元组传递到Terminal节点时,表示该Terminal节点对应的规则被激活。

RETE网络的构建

Rete算法的编译结果是创建了规则集对应的Rete网络,它是一个事实可以在其中流动的图。创建rete网络的过程如下:

  1. 创建根节点;
  2. 加入一条规则

    a. 取出规则中的一个模式 ,(模式就是规则中的最小一个匹配项例如(age>10,age<20)拿么age>10 就是一个模式,age<20 就是另一个模式。)检查模式中的参数类型,如果是新类型(也就是新的fact类型),则加入一个类型节点;
    b. 检查模式对应的Alpha节点是否已存在,如果存在则记录下节点位置,如果没有则将模式作为一个 Alpha节点加入到网络中,同时根据Alpha节点的模式建立Alpha内存表;
    c. 重复b直到所有的模式处理完毕;
    d. 组合Beta节点,按照如下方式:Beta左输入节点为Alpha(1),右输入节点为Alpha(2) 。Beta(i)左输入节点为Beta(i-1),右输入节点为Alpha(i) i>2 并将两个父节点的内存表内联成为自己的内存表;
    e. 重复 d 直到所有的 Beta 节点处理完毕;
    f. 将动作(Then 部分)封装成叶节点(Action 节点)作为 Beta(n) 的输出节点;
  3. 重复 2 直到所有规则处理完毕

按照上面创建rete网络的算法,生成规则3

rule "规则3:账户余额小于100的北苑路姓张的学生"
  when
    $account:Account(balance<100,type=Account.Type.学生)
    $customer:Customer(accounts contains $account)
    $addr:Addr(street="北苑路",customers contains $customer)
  then
    print("账户余额小于100的北苑路姓张的学生");
end

规则3对应的rete网络如下:
这里写图片描述

运行时执行

  1. 从工作内存中取一工作存储区元素WME(Working Memory Element,简称WME)放入根节点进行匹配。WME是为事实建立的元素,是用于和非根结点代表的模式进行匹配的元素。
  2. 遍历每个alpha节点(含ObjectType节点),如果alpha节点约束条件与该WME一致,则将该WME存在该alpha节点的匹配内存中,并向其后继节点传播。
  3. 对alpha节点的后继结点继续(2)的过程,直到alpha内存所有通过匹配的事实保存在alpha内存中。
  4. 对每个beta节点进行匹配,如果单个事实进入beta节点左部,则转换成一个元素的元组存在节点左侧内存中。如果是一个元组进入左部,则将其存在左内存中。如果一个事实进入右侧,则将其与左内存中的元组按照节点约束进行匹配,符合条件则将该事实对象与左部元组合并,并传递到下一节点。bate结点有left存储区和right存储,其中left存储区是beta内存,right存储区是alpha内存。存储区储存的最小单位是WME。
  5. 重复(4)直到所有beta处理完毕,元组对象进入到Terminal节点。对应的规则被触活,将规则后件加入议程(Agenda)。
  6. 对Agenda里的规则进行冲突消解,选择合适的规则执行。

Rete算法的特点

rete算法通过共享规则节点和缓存匹配结果,获得产生式推理系统在时间和空间上的性能提升。

1、状态保存

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

2、节点共享

另一个特点就是不同规则之间含有相同的模式,从而可以共享同一个节点。Rete网络的各个部分包含各种不同的节点共享。

3、节点索引

索引方法是指对rete网络的节点建立当前节点对后继的索引,在事实断言时可以通过索引快速找到对应的后继节点而无需逐个查 找。drools在rete的面向对象版本rete-oo算法中对ObjectType节点增加后继alpha节 点的索引,以事实的属性为key,alpha节点为value,这样在事实通过类型节点验证后可以迅速找到对应的alpha节点进行断言。
同样,对beta节点也可以建立索引,beta节点的索引主要是针对节点左右内存的查询。当一个事实传递到beta节点的右内存中时,需要与该节点的左内存进行连接操作,即遍历左侧内存中的事实元组,找到符合节点约束的事实进行连接。该过程的遍历查找效率较低,将beta内存分成若干单元,每个单元分配一个id;对右侧的事实用哈希函数求索引,该索引就是某个单元的位置,通过索引快速找到相应单元进行匹配,如果不在该分区,则将该对象组成一个新的单元加入左内存。

Rete 算法的不足

  1. 存在状态重复保存的问题,比如匹配过模式1和模式2的事实要同时保存在模式1和模式2的节点缓存中,将 占用较多空间并影响匹配效率。
  2. 事实的删除与事实的添加顺序相同, 除了要执行与事实添加相同的计算外, 还需要执行查找, 开销很高。rete的一个主要缺点就是不适合处理快速变化的数据和规则。主要表现在:
1.数据变化引起节点保存的临时事实频繁变化,这将让rete失去增量匹配的优势。
2.数据的变化使得对规则网络的种种优化方法如索引、条件排序等失去效果。
  1. rete算法使用了alpha内存存储已计算的中间结果, 以牺牲空间换取时间, 从而加快系统的速度。然而当处理海量数据与规则时,beta内存根据规则的条件与事实的数目而成指数级增长, 所以当规则与事实很多时, 会耗尽系统资源。
  2. 规则引擎不能处理缺失的数据及模糊的逻辑。例如规则“如果年级大则容易患中风”。产生式推理系统将不能精确表达“年级大”及“容易”这样的概念,相应的推理也不能得到精确的结果。这种场合下,算法变得很脆弱。

参考:

基于Rete算法的规则引擎Drools的研究

Drools规则工作流引擎全面开发教程

Rete算法:研究现状与挑战

猜你喜欢

转载自blog.csdn.net/lihuayong/article/details/82712584