产生式规则和Rete算法解析

    Rete可以发音为REH-te或者RAY-tay,在拉丁语中有“网络”的含义,Rete算法是Charles Forgy博士1974年发明的一个算法。后来成为了产生式规则系统(Production Rule System)的大脑。Drools就是基于产生式规则系统演化而来的。

产生式规则

    产生式规则是一种常用的知识表示方法,它以"IF-THEN"的形式表现了因果关系。这种形式的规则反映了人类求解(一类?)问题的行为特征,可以通过循环的应用这些规则来解决问题。

……
R3:IF 某动物是有蹄类动物 AND 有长脖子 AND 有长腿 AND 身上有暗斑点 THEN 该动物是长颈鹿(问题解决)
R4:IF 某动物是有蹄类动物 AND 身上有黑色条纹 THEN 该动物是斑马(问题解决)
……
R8:IF 动物是哺乳动物 AND 嚼反动物 THEN 该动物是有蹄类动物
……
R10:IF 某动物有奶 THEN该动物是哺乳动物
……

    例如有以上一些产生式规则,给出"有奶"、"嚼反"、"长脖子"、"长腿"、"身上有暗斑点"条件(也称为事实 facts),就可以求解出问题的答案是“长颈鹿”。

    对于此类问题,自然想到的实现方法是逐条检查规则,但是如上面的例子,有些知识是在推理的过程中得到的,如“哺乳动物”、“蹄类动物”,而规则不一定按照理想的顺序排列,为了能解决问题,只能循环多次,直到解决问题。对于庞大的规则集,这样做显然效率是非常低的。Rete算法为产生式规则系统提供了非常高效的实现。

产生式规则系统结构

    在介绍Rete算法之前,简单介绍以下产生式规则系统的结构。如图所示,规则存储于产生式内存(Production Memory),需要评估的事实(facts)被插入工作内存(Working Memory)中,在其中被修改或撤出。一个含有大量规则和事实的系统可能导致在一次事实评估中,多条规则为真,这种情形被称为冲突。代理(Agenda)将使用冲突解决策略管理冲突规则的执行顺序。


Rete算法

    Rete算法可以分为规则编译和运行时执行两个部分,其中编译算法是Rete算法的精髓所在,描述了如何处理规则生成一个高效的鉴别网络(Discrimination network)。鉴别网络可以理解为用于过滤在其中传递的数据的网络。Forgy博士描述了Rete算法网络中的四类节点:


  • 根节点:所有对象进入网络的入口,在一个网络中只有一个根节点。
  • 单输入节点:可分为ObjectTypeNode, AlphaNode, LeftInputAdapterNode等。
  • 双输入节点:包含JoinNode和NotNode。JoinNode和NotNode也属于用于比较两个对象和其域的BetaNodes。
  • 终端节点:到达一个终端节点,表示单条规则匹配了所有的条件,网络中有多个终端节点。当单条规则中有or时,也会产生多个终端节点。

ObjectTypeNode

事实从根节点进入Rete网络后,会立即进入ObjectTypeNode节点,ObjectTypeNode提供了按对象类型过滤对象的能力,通过此类节点可使规则引擎不做额外的工作。如下图,Cheese类型的事实进入网络后,只需经过Cheese ObjectTypeNode之后的节点。

AlphaNode

AlphaNode节点的作用是评估字面的条件,如下图,评估了Cheese事实的name和strength属性值。AlphaNode之间是串行的,即只要其中一个节点不满足,事实就被过滤掉了。

JoinNode和LeftInputAdapterNode

如前所述,双输入节点JoinNode是一类BetaNode,BetaNode的输入被称作左输入和右输入,其中左输入通常是一个对象列表(元组),而右输入是一个单个对象,可以实现对象是否在列表中存在的检查。LeftInputAdapterNode的作用是输入一个对象,传播为一个单对象列表(元组)。如图所示,JoinNode的左输入为一个经过LeftInputAdapterNode传播后的列表,右输入为一个Person对象。

Drools规则和Rete算法的例子

// rule 1
when
    Cheese( $cheddar : name == "cheddar" )
    $person : Person( favouriteCheese == $cheddar )
then
    System.out.println( $person.getName() + " likes cheddar" );
end
// rule 2
when
    Cheese( $cheddar : name == "cheddar" )
    $person : Person( favouriteCheese != $cheddar )
then
    System.out.println( $person.getName() + " does not like cheddar" );
end


    图示的Rete网络除了展示了代码块中的Drools规则,还体现了Rete算法中节点共享的特征,此特征减少了网络中结点的冗余。

参考资料

1. 产生式规则表示法

2. 产生式表示法

3. Drools官方文档

4. Rete算法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章