规则引擎的会话状态

1.概述
规则引擎,顾名思义通过执行指定的规则集合,得到一系列结果。简单地说,存在业务规则集合(r1,r2…rn),数据集合(d1,d2…dn),规则之间是独立的,规则引擎进行模式匹配,并执行匹配的规则。根据不同的匹配过程,可以把规则引擎分为两种,无状态会话(stateless session)和有状态会话(stateful session)。

2.无状态会话(Stateless session)
无状态会话的规则引擎,不会进行推理。无状态的规则引擎,等价于顺序处理数据的函数方法集合,而且仅仅执行一遍函数集合。按照顺序执行函数集合后,得到期望的结果集合。
无状态会话不保存状态,为了执行规则引擎,初始时必须加入所有对象,并且在执行的过程中不会加入新的对象。由于对象集合没有变化,所以规则集合仅仅需要执行一次。

2.1适用场景:
(1) 校验过程,由校验规则构成规则集合。
(2) 计算过程,由计算公式等构成规则集合。
(3) 路由和过滤,由路由规则和过滤规则构成规则集合。

2.2 实例说明(实例都来自Drools的官方用户手册中)
以Drools的开源实现,说明无状态会话的规则引擎如何使用。举一个驾照申请的例子,假定只有年龄大于18岁的申请者是有效的。那么,Drools的规则可以这么写:
package com.company.license
rule "Is of valid age"
when
$a : Applicant( age < 18 )
then
$a.setValid( false );
end

简单解释下这个规则,when表示规则,then表示结果。这个规则的意思是:在Applicant对象中,age属性值小于18时,valid属性置为false。
Drools的规则加载过程,通过KnowledgeBuilder和KnowledgeBase完成。KnowledgeBuilder负责对规则进行解析,解析的结果保存在KnowledgeBase中。假定上述的规则保存在licenseApplication.drl中,那么Drools的加载过程如下。
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("licenseApplication.drl",getClass()),ResourceType.DRL );
if ( kbuilder.hasErrors() ) {
    System.err.println( kbuilder.getErrors().toString() );
}
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );

规则加载完成之后,如果规则解析的过程中不存在错误。那么,可以新建一个会话,然后根据数据匹配和执行规则。
StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
Applicant applicant = new Applicant( "Mr John Smith", 16 );
assertTrue( applicant.isValid() );
ksession.execute( applicant );
assertFalse( applicant.isValid() );

上面的代码新建了一个无会话状态的规则引擎,当对Applicant对象执行了规则之后,Applicant对象的Valid属性被置为False。

3.有状态会话(stateful session)
有状态会话,能够在多次规则执行的时候保存状态。不同于无状态的会话,有状态的会话存在时间更长,当数据发生变化以后,会重复执行规则的匹配。也就是说,它们之间最大的区别在于,有状态会话存在推理过程。如果一条规则改变了数据,那么所有规则可能需要重新匹配一次。

3.1适用场景:
(1) 监控,例如股票行情的监控和分析。
(2) 诊断,医学诊断。
(3) 物流,包裹的运输和投递。

3.2实例说明
举一个房间火警的例子,说明有状态会话的特征。系统中有4种类型,分别表示房间、自动灭火装置、火、警报。
public class Room {
private String name
// getter and setter methods here
}
public classs Sprinkler {
private Room room;
private boolean on;
// getter and setter methods here
}
public class Fire {
private Room room;
// getter and setter methods here
}
public class Alarm {
}

从上面的代码,我们可以看到每种类型的实体对象不再唯一。可能有多个房间,每个房间有一个自动灭火装置,所有房间共用一个警报。这种情况下,对象之间的关系。
存在如下规则:
规则一、当某个房间起火时,灭火装置自动打开。从规则引擎方面理解,有Filre类型的对象加入到会话中时,对应房间的Sprinkler对象的开关打开。规则描述如下:
rule "When there is a fire turn on the sprinkler"
when
Fire($room : room)
$sprinkler : Sprinkler( room == $room, on == false )
Then
modify( $sprinkler ) { setOn( true ) };
System.out.println( "Turn on the sprinkler for room " + $room.getName() );
end

规则二、当火被扑灭的时候,那么检查并关闭每个房间的灭火装置。对应的,规则引擎中不存在Fire类型对象,那么检查并关闭每个Room类型对象对应的Sprinkler对象中的开关。规则描述如下:
rule "When the fire is gone turn off the sprinkler"
when
$room : Room( )
$sprinkler : Sprinkler( room == $room, on == true )
not Fire( room == $room )
then
modify( $sprinkler ) { setOn( false ) };
System.out.println( "Turn off the sprinkler for room " + $room.getName() );
End

规则三、只要有火灾存在,那么系统中唯一的警报发出告警。相对应的,规则引擎中存在Fire类型对象,那么该规则向session中添加Alarm类型对象。对应规则描述如下:
rule "Raise the alarm when we have one or more fires"
when
exists Fire()
then
insert( new Alarm() );
System.out.println( "Raise the alarm" );
End

规则四、当所有火灾被扑灭之后,警报关闭。相对应的,规则引擎中不存在Fire对象,移除Alarm类型的对象。
rule "Cancel the alarm when all the fires have gone"
when
not Fire()
$alarm : Alarm()
then
retract( $alarm );
System.out.println( "Cancel the alarm" );
End

规则五、没有火灾发生时,系统状态是OK的。对应规则引擎中,没有Alarm类型的对象,并且灭火装置处在关闭状态。
rule "Status output when things are ok"
when
not Alarm()
not Sprinkler( on == true )
then
System.out.println( "Everything is ok" );
End

规则的加载同于无状态会话的过程。规则引擎的创建:
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newClassPathResource( "fireAlarm.drl", getClass() ),
ResourceType.DRL );
if ( kbuilder.hasErrors() ) {
System.err.println( builder.getErrors().toString() );
}
kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();

规则引擎的执行过程一、:
String[] names = new String[]{"kitchen", "bedroom", "office", "livingroom"};
Map<String,Room> name2room = new HashMap<String,Room>();
for( String name: names ){
Room room = new Room( name );
name2room.put( name, room );
ksession.insert( room );
Sprinkler sprinkler = new Sprinkler( room );
ksession.insert( sprinkler );
}
ksession.fireAllRules()

这段代码的执行过程中,仅仅匹配了规则五。执行结果是,Everything is ok。
规则引擎的执行过程二:
Fire kitchenFire = new Fire( name2room.get( "kitchen" ) );
Fire officeFire = new Fire( name2room.get( "office" ) );
FactHandle kitchenFireHandle = ksession.insert( kitchenFire );
FactHandle officeFireHandle = ksession.insert( officeFire );
ksession.fireAllRules();

这段代码向会话中,放入两个Fire类型的对象,规则一和三匹配成功。
> Raise the alarm
> Turn on the sprinkler for room kitchen
> Turn on the sprinkler for room office

4.小结
有状态会话和无状态会话之间,主要区别在于是否会动态添加或者移除对象和规则的推理。会话状态的选择完全取决于业务的需求。如果在规则执行之前,就能确定所有的对象,那么多数情况下需要使用无状态的规则引擎。反之,如果规则引擎需要多次执行,每次都依赖之前的状态,那么选择有状态的规则引擎是很恰当的。


参考文档:
1.Drools Expert User Guide
2.http://www.ibm.com/developerworks/cn/java/j-java-rules/index.html?ca=dwcn-newsletter-java

猜你喜欢

转载自bernardlee.iteye.com/blog/1415407