19.10. 定制 Doom 示例决策(返回链和递归)
Doom 示例决策集的 House 演示了决策引擎如何使用向后兼容性和递归来访问分层系统中定义的目标或子组。
以下是 Doom 示例 House 的概述:
-
名称 :
后链
-
主类 :
org.drools.examples.backwardchaining.HouseOfDoomMain
(在src/main/java
中) -
模块 :
drools-examples
- 类型 :Java 应用程序
-
规则文件:
org.drools.examples.backwardchaining.BC-Example.drl
(在src/main/resources
中) - 目标 :演示后链和递归
后链规则系统是一个目标驱动的系统,从决策引擎尝试满足的目标驱动的系统开始,通常使用递归。如果系统无法访问语音或目标,它会搜索子组,这是完成当前目标的一部分。系统会继续这个过程,直到满足初始目标或满足所有子状态为止。
相反,转发链规则系统是一个数据驱动的系统,它以决策引擎的工作内存中的事实开始,并对这一事实的更改做出响应。当对象插入到工作内存中时,因更改计划执行而满足的任何规则条件。
Red Hat Process Automation Manager 中的决策引擎使用正向和后链来评估规则。
下图演示了,决策引擎如何使用转发链和逻辑流中的向链段来评估规则:
图 19.27. 使用正向和后链的规则评估逻辑
Doom 示例的 House 使用各种类型的查询的规则来查找托管中的房间和项目的位置。示例类 Location.java
包含示例中使用的 项
和位置
元素。示例类 HouseOfDoomMain.java
将项目或房间插入到其各自的位置,并执行规则。
HouseOfDoomMain.java 类的项目和位置
示例规则依赖于向向链和递归来确定托管结构中的所有项目和房间的位置。
下图演示了 Doom 的 House 的结构,以及其中的项目和房间:
图 19.28. Doom 结构的托管
要执行示例,请在 IDE 中作为 Java 应用程序运行 org.drools.examples.backwardchaining.HouseOfDoomMain
类。
执行后,以下输出会出现在 IDE 控制台窗口中:
IDE 控制台中的执行输出
示例中的所有规则都触发,以检测托管中的所有项目的位置,并在输出中打印各个项目的位置。
递归查询和相关规则
递归查询重复搜索数据结构的层次结构,以获取元素之间的关系。
在 Doom 示例中的 House 中,BC-Example.drl
文件包含一个 isContainedIn
查询,该查询中大多数规则都使用它递归评估插入到决策引擎中的数据的数据结构:
BC-Example.drl 中的递归查询
query isContainedIn( String x, String y ) Location( x, y; ) or ( Location( z, y; ) and isContainedIn( x, z; ) ) end
query isContainedIn( String x, String y )
Location( x, y; )
or
( Location( z, y; ) and isContainedIn( x, z; ) )
end
规则 "go"
会输出插入到系统中的每个字符串,以确定如何实施项目,规则 "go1"
调用查询 是ContainedIn
:
规则 "go" 和 "go1"
示例将 "go1"
字符串插入到决策引擎中,并激活 "go1"
规则来检测该项目 响应者
位于位置 House
中:
插入字符串和触发规则
ksession.insert( "go1" ); ksession.fireAllRules();
ksession.insert( "go1" );
ksession.fireAllRules();
IDE 控制台中的规则 "go1" 输出
go1 Office is in the House
go1
Office is in the House
传输冲突规则
传输是父元素中包含的元素之间的关系,它在分级结构中有多个级别。
规则 "go2"
标识 Drawer
和 House
的传输关系,即 Drawer
位于 House
内的 Desk
中。
示例将 "go2"
字符串插入到决策引擎中,并激活 "go2"
规则来检测该项目 Drawer
最终会在位置 House
中:
插入字符串和触发规则
ksession.insert( "go2" ); ksession.fireAllRules();
ksession.insert( "go2" );
ksession.fireAllRules();
IDE 控制台中的规则"go2"输出
go2 Drawer is in the House
go2
Drawer is in the House
决策引擎根据以下逻辑决定此结果:
-
查询递归搜索存放中的多个级别,以检测
Drawer
和House
之间的传输冲突。 -
查询使用
Location (x, y;)
,而是使用(z, y;)
,因为Drawer
不直接在House
中。 -
z
参数当前未绑定,这意味着它没有值并返回参数中的所有内容。 -
y
参数当前绑定到House
,因此z
返回Office
和Kitchen
。 -
如果
Drawer
位于响应者
,查询会从印度收集信息并递归检查。为这些参数调用查询行
isContainedIn (x, z;)
。 -
印度没有直接存在
Drawer
实例
,因此找不到任何匹配项。 使用
z
unbound 时,查询会返回响应者中的数据,并确定 z == Desk。isContainedIn(x==drawer, z==desk)
isContainedIn(x==drawer, z==desk)
Copy to Clipboard Copied! Toggle word wrap Toggle overflow isContainedIn
查询递归搜索三次,第三个时间则查询会检测Desk
中的Drawer
实例。Location(x==drawer, y==desk)
Location(x==drawer, y==desk)
Copy to Clipboard Copied! Toggle word wrap Toggle overflow -
在第一个位置上匹配后,查询会递归搜索结构,以确定
Drawer
是否在Desk
中,Desk
位于印度,且响应者位于House
中。因此,
Drawer
位于House
中,规则满足。
重新主动查询规则
被动查询搜索数据结构的层次结构,以获取元素之间的关系,并在修改结构中的元素时动态更新。
规则 "go3"
的功能作为一个重新主动查询,它通过传输冲突来检测响应中是否存在新项目密钥:该机构中的 Drawer
中的密钥
。
规则 "go3"
示例将 "go3"
字符串插入到决策引擎中,并激活 "go3"
规则。最初,此规则不满足,因为托管结构中没有项目密钥,因此规则不会生成任何输出。
插入字符串和触发规则
ksession.insert( "go3" ); ksession.fireAllRules();
ksession.insert( "go3" );
ksession.fireAllRules();
IDE 控制台中的规则"go3"输出(不满意)
go3
go3
然后,该示例在位置 Drawer
中插入一个新项目密钥,它位于 印度
。这个更改满足
"go3"
规则中的传输冲突,输出会相应地填充。
插入新项目位置和触发规则
ksession.insert( new Location("Key", "Drawer") ); ksession.fireAllRules();
ksession.insert( new Location("Key", "Drawer") );
ksession.fireAllRules();
IDE 控制台中的规则"go3"输出(满意)
Key is in the Office
Key is in the Office
此更改还在查询包含在后续递归搜索的结构中添加另一个级别。
在规则中使用未绑定参数的查询
具有一个或多个未绑定参数的查询会返回查询定义的(绑定)参数中的所有未定义(unbound)项目。如果查询中的所有参数都未绑定,则查询会返回查询范围内的所有项目。
规则 "go4"
使用 unbound 参数操作来搜索绑定参数 响应中的
所有项目,而不是使用 bound 参数搜索响应者中的特定项目:
规则"go4"
示例将 "go4"
字符串插入到决策引擎中,并激活 "go4"
规则,以返回响应者中的所有项目:
插入字符串和触发规则
ksession.insert( "go4" ); ksession.fireAllRules();
ksession.insert( "go4" );
ksession.fireAllRules();
IDE 控制台中的规则"go4"输出
规则 "go5"
使用 unbound 参数 和位置
在整个 House
数据结构中搜索所有项目及其位置:
规则 "go5"
示例将 "go5"
字符串插入到决策引擎中,并激活 "go5"
规则来返回 House
数据结构中的所有项目及其位置:
插入字符串和触发规则
ksession.insert( "go5" ); ksession.fireAllRules();
ksession.insert( "go5" );
ksession.fireAllRules();
IDE 控制台中的规则"go5"输出