在
JBoss Rules 学习(一):什么是Rule
中,我们介绍了JBoss Rules中对Rule的表示,其中有很多JBoss Rules框架的专业术语,下面对这些术语作出进一步的解释,可以使JBoss Rules更加容易理解。
1.Rete
算法
:
Rete
在拉丁语中是
”net”
,有网络的意思。
RETE
算法可以分为两部分:规则编译(
rule compilation
)和运行时执行(
runtime execution
)。
编译算法描述了规则如何在
Production Memory
中产生一个有效的辨别网络。用一个非技术性的词来说,一个辨别网络就是用来过滤数据。方法是通过数据在网络中的传播来过滤数据。在顶端节点将会有很多匹配的数据。当我们顺着网络向下走,匹配的数据将会越来越少。在网络的最底部是终端节点(
terminal nodes
)。在
Dr Forgy
的
1982
年的论文中,他描述了
4
种基本节点:
root , 1-input, 2-input and terminal
。
根节点是所有的对象进入网络的入口。然后,从根节点立即进入到
ObjectTypeNode
。
ObjectTypeNode
的作用是使引擎只做它需要做的事情。例如,我们有两个对象集:
Account
和
Order
。如果规则引擎需要对每个对象都进行一个周期的评估,那会浪费很多的时间。为了提高效率,引擎将只让匹配
object type
的对象通过到达节点。通过这种方法,如果一个应用
assert
一个新的
account
,它不会将
Order
对象传递到节点中。很多现代
RETE
实现都有专门的
ObjectTypeNode
。在一些情况下,
ObjectTypeNode
被用散列法进一步优化。
1-input
节点通常被称为
AlphaNode
。
AlphaNodes
被用来评估字面条件(
literal conditions
)。虽然,
1982
年的论文只提到了相等条件(指的字面上相等),很多
RETE
实现支持其他的操作。例如,
Account.name = = “Mark”
是一个字面条件。当一条规则对于一种
object type
有多条的字面条件,这些字面条件将被链接在一起。这是说,如果一个应用
assert
一个
account
对象,在它能到达下一个
AlphaNode
之前,它必须先满足第一个字面条件。在
Dr. Forgy
的论文中,他用
IntraElement conditions
来表述。上一段提到的
ObjectTypeNode
是一种特殊的
AlphaNode
。
2-input
节点通常被称为
BetaNode
。
BetaNodes
被用来对
2
个对象进行对比。这两个对象可以是同种类型,也可以是不同类型。一个
BetaNode
的左边输入通常是
a list of objects
。右边输入是
a single object
。在一些情况下,一个规则引擎可能实现一些
BetaNodes
来处理
existential conditions (
‘与’条件
)
和
negated conditional element
(‘非’条件)。很多现代的
RETE
实现通过
hash
或
b-tree indexes
来优化
BetaNodes
。
Terminal nodes
被用来表明一条规则已经匹配了它的所有条件(
conditions
)。在一些情况下,一条带有“或”条件的规则可以有超过一个的
terminal node
。从一个
RETE
网络的观点来看,一条带有“或”条件的规则实际上只是
2
个拥有很多共享节点的节点。
RETE
算法的第二个部分是运行时(
runtime
)。当一个应用
assert
一个对象,引擎将数据传递到
root node
。从那里,它进入
ObjectTypeNode
并沿着网络向下传播。当数据匹配一个节点的条件,节点就将它记录到相应的内存中。这样做的原因有以下几点:主要的原因是可以带来更快的性能。虽然记住完全或部分匹配的对象需要内存,它提供了速度和可伸缩性的特点。当一条规则的所有条件都满足,这就是完全匹配。而只有部分条件满足,就是部分匹配。(我觉得引擎在每个节点都有其对应的内存来储存满足该节点条件的对象,这就造成了如果一个对象是完全匹配,那这个对象就会在每个节点的对应内存中都存有其映象。)
<!--[if !supportEmptyParas]-->
2.Leaps
算法:
Production systems
的
Leaps
算法使用了一种“
lazy
”方法来评估条件(
conditions
)。一种
Leaps
算法的修改版本的实现,作为
Drools v3
的一部分,尝试结合
Leaps
和
RETE
方法的最好的特点来处理
Working Memory
中的
facts
。
古典的
Leaps
方法将所有的
asserted
的
facts
,按照其被
asserted
在
Working Memory
中的顺序(
FIFO
),放在主堆栈中。它一个个的检查
facts
,通过迭代匹配
data type
的
facts
集合来找出每一个相关规则的匹配。当一个匹配的数据被发现时,系统记住此时的迭代位置以备待会的继续迭代,并且激发规则结果(
consequence
)。当结果(
consequence
)执行完成以后,系统就会继续处理处于主堆栈顶部的
fact
。如此反复。
<!--[if !supportEmptyParas]-->
3.RuleBase:
一个
RuleBase
包含了多个将被使用的规则包(
packages of rules
)。当规则改变时,一个
rulebase
将被产生并且缓存,直到规则再次变化。
一个
rulebase instance
是线程安全的,所有你可以在你的应用中,让一个
rulebase instance
在多个线程中共享。对于一个
rulebase
的最通常的操作是产生一个新的
WorkingMemory
。
这个
rulebase
保持着到它所产生的
WorkingMemoryd
的弱引用,所以在长时间运行的
WorkingMemory
中,如果
rules
发生改变,这些
WorkingMemory
可以即使的根据最新的
rules
进行更新,而不必重启
WorkingMemory
。
4.WorkingMemory:
WorkingMemory
基本上就是已经载入所有的
rules
,并且准备启动的
rule engine
。它保持了所有被
asserted
进
WorkingMemory
的数据的引用,直到取消(
retracted
)。并且它是与你的系统进行交互的地方。
WorkingMemory
是有状态对象。它们的生命周期可长可短。如果从一个短生命周期的角度来同一个引擎进行交互,意味着你可以使用
RuleBase
对象来为每个
session
产生一个新的
WorkingMemory
,然后在结束
session
后
discard
这个
WorkingMemory
(产生一个
WorkingMemory
是一个廉价的操作)。另一种形式,就是在一个相当长的时间中(例如一个
conversation
),保持一个
WorkingMemory
,并且对于新的
facts
保持持续的更新。
4.1 Facts
Facts
是从你的应用中,被
assert
进
WorkingMemory
中的对象(
beans
)。
Facts
是规则可以访问的任意的
java
对象。规则引擎中的
facts
并不是“
clone
”
facts
,它只是持有到你的应用中数据的引用。
4.2 Assertion
“Assertion”
是将
facts
告诉
WorkingMemory
的动作,例如
WorkingMemory.assertObject (yourObject)
。当你
assert
一个
fact
。它将被检查是否匹配规则。当你完成
assert facts
之后,你还要调用“
fireAllRules()
”方法来启动匹配。
(
WorkingMemory.assertObject(yourObjcet)
只是进行
assertion
的一种
regular
方法,还存在有一种称为
logical assertion
的动作)。
4.3 Retraction
基本上就是
assert
的逆操作。当你
retract
一个
fact
,
WorkingMemory
将不再跟踪那个
fact
。任何依赖那个
fact
的
rules
将不被激活。注意:完全有可能存在某条规则是依赖于一个
fact
的“不存在”(
non existence
)。在这种情况下,
retract
一个
fact
将导致一条规则被激活。
4.4 Modification
规则引擎必须知道什么时候一个
fact
被改变了,因为依赖此
fact
的
rule
会因此而被再次激发。当你修改一个
fact
的时候,就告诉了规则引擎它的状态已经改变了。
4.5 Globals
Globals
是一个能够被传进规则引擎的命名的对象。大多数这些对象被用来作为静态信息或服务。这些服务被用在一条规则的
RHS
,或者可能是从规则引擎返回对象的一种方法。
4.6 Property Change Listener
如果你的
fact
对象是
java bean
,你可以为它们实现一个
property change listener
,然后把它高数规则引擎。这意味着,当一个
fact
改变时,规则引擎将会自动知道,并进行响应的动作。
Proxy libraries
将会帮助实现这一切。
4.7 Stateless and Statefull Sessions
基于
RETE
算法的规则引擎是有状态的规则引擎。有状态带来的好处是改变能够被通知和累计
facts
(
accumulating facts
)。
尽管如此,在很多情况下,所有提供给规则引擎的的
facts
都是最新的,紧接着规则被激活。在这种情况下仅仅需要一种无状态的模式。
JSR-94 API
指定了有状态和无状态的模式,但是在
native API
中的等价物仅仅是创建一个新的
WorkingMemory
实例,然后当
session
结束时删除它。
<!--[if !supportEmptyParas]-->
5. Agenda:
Agenda
是
RETE
的一个特点。它是内存中的一个区域,在规则和匹配的
facts
被激发之前,它们被保存在这里,称为“
activations
”。
引擎工作在一个“
2
阶段”模式下:
<!--[if !supportLists]--> 1) <!--[endif]--> WorkingMemory actions :assert新的facts,修改存在的facts和retract facts都是WorkingMemory actions。这些动作从一条规则的RHS或是java code中被触发。
<!--[if !supportLists]--> 2) <!--[endif]--> Agenda evaluation(rule actions在这里被激发)。
注意:这个过程是一个轮流发生的过程,一条规则的激发可能引起
WorkingMemory actions
的发生。当
WorkingMemory actions
发生时,应该没有规则正在被激发。
fireAllRules()
方法引起
Agenda evaluation
,最终“
activations
”激发。这个过程一直重复直到
Agenda
被清空,此时控制权就回到应用程序中。
5.1 Conflict Resultion
当有多条
rules
在
agenda
中,就需要解决冲突。当激发一条规则时,会对
WorkingMemory
产生副作用。规则引擎需要知道规则要以什么顺序来激发(例如,激发
rule A
可能会引起
rule B
被从
agenda
中移除。)
Drools
采取的冲突解决策略有
4
种,按照优先级排列如下:
Salience
,
FIFO
(先进先出),
Total Recency
和
Load order
。
优先级最高,也是最易懂的策略是“
Salience
”,即优先级,
user
可以为某个
rule
指定一个高一点的优先级(通过附给它一个比较大的数字)。高
Salience
的
rule
将会被优先激发。
优先级最低的策略是
Load order
,就是按照
rule
被声明的顺序。
5.2 Agenda Groups
Agenda Groups
是划分
Agenda
中
rules
(其实是“
activations
”)的一种方法。在任意一个时刻,只有一个
group
拥有“
focus
”,这意味着只有在那个
group
中的
activations for rules
才是有效的。
5.3 Filters
Filter
是
filter
接口的可选实现,用来允许或禁止一个
activation
能够被激发。