Fact是指在Drools规则应用当中,将一个普通的JavaBean插入到规则的WorkingMemory当中后的对象。
规则可以对Fact对象进行任意的读写操作,当一个JavaBean插入到WorkingMemory当中变成Fact之后,Fact对象不是对原来的JavaBean对象进行Clon(克隆),而是原来
JavaBean对象的引用。
规则在进行计算的时候需要用到应用系统当中的数据,这些数据设置在Fact对象当中,然后将其插入到
规则的WorkingMemory当中,这样在规则当中就可以
通过对Fact对象数据的读写,从而实现对应用数据的读写操作。一个Fact对象通常是
一个具有getter和setter方法的POJO对象,通过这些getter和setter方法可以方便的实现对Fact对象的读写操作,所以我们可以简单的把Fact对象理解为规则与应用系统数据交互的桥梁或通道。
当Fact对象插入到WorkingMemory当中后,会与当前WorkingMemory当中所有的规则进行匹配,同时返回一个FactHandler对象。FactHandler对象是插入到WorkingMemory当中Fact对象的引用句柄,通过FactHandler对象可以实现对对应的Fact对象的删除及修改等操作。
规则文件
在 Drools 当中,一个标准的规则文件就是一个以“.drl”结尾的文本文件,由于它是一 个标准的文本文件,所以可以通过一些记事本工具对其进行打开、查看和编辑。规则是放在规则文件当中的,一个规则文件可以存放多个规则,除此之外,在规则文件当中还可以存放用户自定义的函数、数据对象及自定义查询等相关在规则当中可能会用到的一些对象。
一个标准的规则文件的结构代码清单。
除 package 之外,其它对象在规 则文件中的顺序是任意的,也就是说在规则文件当中必须要有一个 package 声明,同时
package 声明必须要放在规则文件的第一行
规则文件当中的 package 和 Java 语言当中的 package 有相似之处,也有不同之处。在 Java 当中 package 的作用是用来对功能相似或相关的文件放在同一个 package 下进行管理,这种 package 管理既有物理上 Java 文件位置的管理也有逻辑上的文件位置的管理,在 Java 当中 这种通过 package 管理文件要求在文件位置在逻辑上与物理上要保持一致;在 Drools 的规则文件当中 package 对于规则文件中规则的管理只限于逻辑上的管理,而不管其在物理上的位置如何,这点是规则与 Java 文件的 package 的区别。
对于同一 package 下的用户自定义函数、自定义的查询等,不管这些函数与查询是否在 同一个规则文件里面,在规则里面是可以直接使用的,这点和 Java 的同一 package 里的 Java 类调用是一样的。
规则语言
一个规则
可以
包含三个部分: 也就是说 这三个部分是可选的。
属性部分:
定义当前规则执行的一些属性等,比如是否可被重复执行、过期时间、生效时间等
条件部分:
即LHS,定义当前规则的条件,如 when Message(); 判断当前workingMemory中是否存在Message对象。
结果部分:
即RHS,这里可以写普通java代码,即当前规则条件满足后执行的操作,可以直接调用Fact对象的方法来操作应用
先从简单的说起
条件部分:
条件部分又被称之为 Left Hand Side,简称为 LHS,下文当中,如果没有特别指出,那么所说的 LHS 均指规则的条件部分,在一个规则当中 when 与 then 中间的部分就是 LHS 部分。在 LHS 当中,可以包含 0~n 个条件,如果 LHS 部分没空的话,那么引擎会
自动添加一 个 eval(true)的条件,由于该条件总是返回 true,所以 LHS 为空的规则总是返回 true。
LHS 部分是由一个或多个条件组成,条件又称之为 pattern(匹配模式),
多个 pattern 之间用可以使用 and 或 or 来进行连接,同时还可以使用小括号来确定 pattern 的优先级
对于一个 pattern 来说“绑定变量名”是可选的,如果在当前规则的 LHS 部分的其它的 pattern 要用到这个对象,那么可以通过为该对象设定一个绑定变量名来实现对其引用,对于 绑定变量的命名,通常的作法是为其添加一个“$”符号作为前缀,这样可以很好的与 Fact 的属性区别开来;绑定变量不仅可以用在对象上,也可以用在对象的属性上面,命名方法与 对象的命名方法相同;“field 约束”是指当前对象里相关字段的条件限制,
规则中 LHS 部分单个 pattern (
模式) 的情形。
规则中“$customer”是就是一个绑定到 Customer 对象的“绑定变量名”,该规则的 LHS 部分表示,
要求 Fact 对象必须是 Customer 类型,该条件满足了那么它的 LHS 会返回 true。
下面这种写法就是包含两种pattern(
模式) :
rule "rule1"
when
$customer:Customer(age>20,gender=='male')
Order(customer==$customer,price>1000)
then
....
end
简单说明一下上面的代码
第一个: pattern(
模式)
有三个约束
- 对象 类型必须是 Cutomer;
- Cutomer 的 age 要大于 20
- Cutomer 的 gender 要是 male
第二个: pattern
(
模式)
有三个约束
- 对象类型必须是 Order;
- Order 对应的 Cutomer 必须是前面的那个 Customer
- 当前这个 Order 的 price 要大于 1000
这两个 pattern 没有符号连接,在 Drools 当中在 pattern 中没有连接符号,那么就用 and 来作为默认连接,所以在该规则的 LHS 部分 中两个 pattern(
模式)
只有都满足了才会返回 true。默认情况下,每行可以用“;”来作为结束符(和 Java 的结束一样),当然行尾也可以不加“;”结尾。
约束连接
对于对象内部的多个约束的连接,可以采用“&&”(and)、“||”(or)和“,”(and)来实现
这三个连接符号如果没有用小括号来显示的定义优先级的话,那么它们的执行顺序是:“
&&”(and)、
“||”(or)和
“,”
表面上看“,”与“&&”具有相同的含义,但是有一点需要注意,“,”与“&&”和“||” 不能混合使用,也就是说在有“&&”或“||”出现的 LHS 当中,是不可以有“,”连接符出 现的,反之亦然
not 非
exists 存在
在使用 or not exists 要注意, 可能会出现短路机制。
Drools提供了十二中类型比较操作符:如果进行常量比较,必须通过eval(条件) 或者对象引用 比较对象属性
> >= < <= == !=
contains| not contains
memberOf | not memberOf
matches | not matches
下面说明一下后面6种的含意
contains: 比较操作符 contains 是用来检查一个 Fact 对象的某个字段(该字段要是一个 Collection 或是一个 Array 类型的对象)是否包含一个指定的对象
语法格式:
Object(field[Collection/Array] contains value)
contains 只能用于对象的某个 Collection/Array 类型的字段与另外一个值进行比较,作为比较的值可以是一个静态的值,也可以是一个变量(绑定变量或者是一个 global 对象)
not contains:not contains 作用与 contains 作用相反,not contains 是用来判断一个 Fact 对象的某个字 段(Collection/Array 类型)是不是包含一个指定的对象,和 contains 比较符相同,它也只能用在对象的 field 当中,举例说明
在判断订单(Order)的时候,要求订单当中不能包含有“手机”的货物,这里的规则对于比较的项就是一个表态固定字符串
memberOf:memberOf 是用来判断某个 Fact 对象的某个字段是否在一个集合(Collection/Array)当中,用法与 contains 有些类似,但也有不同
memberOf 的语法如下:
Object(fieldName memberOf value[Collection/Array])
可以看到 memberOf 中集合类型的数据是作为被比较项的,集合类型的数据对象位于 memberOf 操作符后面,同时在用 memberOf 比较操作符时被比较项一定要是一个变量(绑定变量或者是一个 global 对象),而不能是一个静态值。
举例说明
not memberOf:该操作符与 memberOf 作用洽洽相反,是用来判断 Fact 对象当中某个字段值是不是中 某个集合(Collection/Array)当中,同时被比较的集合对象只能是一个变量(绑定变量或 global 对象)。 如何给全局变量赋值:ksession.setGlobal("orderNames",list2);
matches:matches 是用来对某个 Fact 的字段与标准的 Java 正则表达式进行相似匹配,被比较的字符串可以是一个标准的 Java 正则表达式,但有一点需要注意,那就是正则表达式字符串当中不用考虑“\”的转义问题
语法如下:
Object(fieldName matches “正则表达式”)
举例说明
简单来说就是模糊查询
该规则是用来查 找所有 Customer 对象的 name 属性是不是以“李”字开头,如果满足这一条件那么就将该 Customer 对象的 name 属性打印出来
not matches:与 matches 作用相反,是用来将某个 Fact 的字段与一个 Java 标准正则表达式进行匹配, 看是不是能与正则表达式匹配。
结果部分
结果部分又被称之为 Right Hand Side,简称为 RHS,在一个规则当中
then 后面部分就是 RHS,
只有在 LHS 的所有条件都满足时 RHS 部分才会执行。
RHS 部分是规则真正要做事情的部分,可以将因条件满足而要触发的动作写在该部分当中,
在RHS当中可以使用 LHS 部分当中定义的绑定变量名、设置的全局变量、或者是直接编写 Java 代码(对于
要用到的 Java 类,
需要在规则文件当中用 import 将类导入后方能使用,这点和 Java 文件的编写规则相同)。
我们知道,在规则当中LHS就是用来放置条件的,所以在RHS当中虽然可以直接编写 Java 代码,但不建议在代码当中有条件判断,如果需要条件判断,那么请重新考虑将其放在 LHS 当中,否则就违背了使用规则的初衷。
在Drools 当中,在RHS里面,提供了一些对当前 Working Memory 实现快速操作的
宏函数或
对象,比如
insert/insertLogical、update 和 retract 就可以实现对当前 Working Memory 中的 Fact 对象进行新增、删除或者是修改;如果您觉得还要使用 Drools 当中提供的其它方法,那么您还可以使用另一外宏对象 drools,通过该对象可以使用更多的操作当前 Working Memory 的方法;同时Drools还提供了一个名为
kcontext 的宏对象,使我们可以通过该对象直接访问当前 Working Memory 的 KnowledgeRuntime。
扩展部分
$p.address.age=10 等同于 $p.getAge().setAge(10) 这也是赋值的一种方式
$customer.accounts[
3
] 等同于 $customer.getAccounts(
3
)
访问Map数据结构
$customerMap[
"123"
] 等同于$customerMap.get[
"123"
]
This
this指向当前的Fact
看起来是没有什么问题,但同sql这种还是有一点点相似的,如果有== 这样的比较符之类的就要把这最严格的放到前面
优化上面规则:
下面是小编的微信转帐二维码,小编再次谢谢读者的支持,小编会更努力的
----请看下方↓↓↓↓↓↓↓
百度搜索 Drools从入门到精通:可下载开源全套Drools教程
深度Drools教程不段更新中:
更多Drools实战陆续发布中………
扫描下方二维码关注公众号 ↓↓↓↓↓↓↓↓↓↓