Drools规则引擎,网上大把相关的文章介绍,但我感觉不够直白,理解有些困难,且知识点没有集中比较分散、有些还是引版本的内容,对与新手来说上手可能比较慢,而且比较容易走弯路,故我在深入研究并实践于项目中后,在空闲时间花费精力整理了这篇文章,分享出来,便大家快速上手。
1. 创建Drools环境(引入Drools相关依赖包、现在都流行spring boot,故最简单有效的依赖才是最好的,kie-spring内部自行依赖了drools相关核心的依赖包)
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-spring</artifactId>
<version>7.55.0.Final</version>
</dependency>
2. 了解Drools语法及其含义(LHS、RHS、Fact)
-
DRL文件基本格式:
package rules.testwrod //包名,必需,这是逻辑上,与物理路径无关 import xxxxx; //可选,导入要使用的类名(还支持直接导入静态方法) global java.util.List myGlobalList;//可选,定义全局变量(该变量由外部setGlobal传入) function getResult(...){ //可选,自定义函数 } query "query_gt_0"(...) //可选,自定义查询(仅只有LHS内容) $result:规则Pattern end rule “test001” //规则名称,必需,且需唯一 when //规则开始关键字,必需 //这里如果为空 则表示 eval(true); LHS内容(即:规则条件) then //规则条件结束关键字,必需,后面部份则是RHS内容(即:规则触发的逻辑) System.out.println(“hello drools!”); end //规则结束关键字
-
涉及的名词解释:
-
LHS:条件部分又被称之为 Left Hand Side,简称为 LHS,在一个规则当中 when 与 then 中
间的部分就是 LHS 部分。在 LHS 当中,可以包含 0~n 个条件,如果 LHS 部分没空的话,
那么引擎会自动添加一个 eval(true)的条件,由于该条件总是返回 true,所以 LHS 为空的规https://www.jianshu.com/p/ccddaff7894a
则总是返回 true。LHS涉及的匹配元素用法如下:-
Pattern 模式,语法:事实类型(约束),其中约束是可选的,如:Person(age>18),意思是:匹配工作内存中是Person类型且age>18,若存在则为true,即命中该条规则;Pattern 模式支持多个,之间使用空格或换行即可;【通俗点:当前工作内存中有没有这个类型的对象(fact)】
-
字段约束,即Pattern 模式中括号中的部份,一般有:单值限制(如:age>18)、复合值限制(Person(sex in (0,1)),注:暂支持in与not in)和多限制(如:age>18 && age<30 或 age ( (> 30 && < 40) || (> 20 && < 25) )) 3种限制模式;字段约束之间支持:||、&&、and、or、,(逗号即为AND)【通俗点:当前工作内中的这个类型(fact)的对象属性还需满足相关的约束条件】
-
条件元素 eval,条件元素 eval 本实上是包罗万象的,它允许执行任何语义代码(返回一个 boolean 原型)【通俗点:动态解释执行代码逻辑,与js的eval有类似功能】
-
条件元素 not,用于检查在工作内存中不存在某东西。把"not"看作“一定没有……”的意思
-
条件元素 exists,用于检查在工作内存中存在某类型(fact)。把"exists"看作“至少有一个……”的意思。(如果匹配到多个事实fact对象,也只会触发执行一次RHS中逻辑)
-
条件元素 forall,用于检查在工作内存中所有的对象(fact)都必需满足Pattern 模式,若有1个不满足,则为false,只有全部满足才为true;(如果匹配到多个事实fact对象,也只会触发执行一次RHS中逻辑)
-
条件元素 from, 让用户指定任意的资源,用于 LHS 模式的数据匹配。这允许引擎在非工作内存数据的基础上进行推断。数据源可以是一个绑定变量的一个子字段,或者方法调用的结果。它是一个超强结构,允许开箱即可与其他应用程序组件或框架集成使用【通俗点:from后面是指定一个自定义的数据源,from前面是from后面结果得到的,类似sql中的select field=value from table;】
-
条件元素 collect,允许规则在来自特定资源或工作内存的一个对象集合上进行推断【通俗点:就是将符合匹配到多个事实fact对象累加到一起形成一个Collection集合】
-
条件元素 accumulate,是一个更灵活强大的 collect 形式,它主要做的事是允许规则迭代整个
一个对象的集合,为每个元素定制执行动作,并在结束时返回一个结果对象, accumulate
既支持预定义的累积函数的使用,或也可以使用内联的自定义代码,简化的语法如下:accumulate( <source pattern 源模式>; <functions 函数 > [;] ),其中函数除了内置的还可以自定义JAVA函数,只需使用import accumulate 类型(该类型需实现AccumulateFunction接口) 自定义方法名;
示例代码:
accumulate(Message(createBy=="zuowj",$id:id);$countNum:count($id);$countNum>1) //含义:查找工作内存中有Message类型的且过滤条件为(createBy=="zuowj")fact事实对象,并取出id,然后对所有的id进行count,最后判断count的结果是否>1,转换为SQL理解就是: //select id from Message where createBy='zuowj' group by id having count(id)>1;这样应该好理解吧!
inline 的语法结构:
,init(),action(),reverse(),result() ):这个表示源模式。用法:也就是我们常用手 Object(xx:XX 属性) 这 个会去匹配每一个源对象。 :用法说明:init 是做初始化用的,简单的说,在 source pattern 遍历 完之后 就已经触发,有点像 for 的开头 : 用法说明:action 会执行所以满足条件的源对象进行操作,像是 for 的方法体。在里面可写 java code : 这是一个可选的被选方言的语义代码块,如果存在,将为不再匹配资 源模式的每个资源对象执行。这个代码块的目的是不做在 块中做的任何计算, 所以,当一个资源对象被修改或删除收时,引擎可能做递减计算,极大地提升了这些操作的 性能 : 返回值,是根据 action 上面两个遍历出来的结果进行一个返 回,这个返回值中也可以进行计算。 : 返回值类型,在返回值的类型再一次进行匹 配,如果匹配不成功则返回 false。
from accumulate(示例代码:
$res:String() from accumulate(Message(createBy=="zuowj",$cont:content),init(String allContent="";),action(allContent +=$cont;),result(allContent)) //含义:for循环遍历工作内存中Message类型且过滤条件为(createBy=="zuowj")的fact对象,初始化设置allConten
-
-