版本7.69
一、环境
1、依赖包
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>6.3.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>6.3.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>6.3.0.Final</version>
</dependency>
第一个org。kie:kie-api依赖包含所有的公共接口暴露出来
KIE平台,由Drools,jBPM,OptaPlanner。
接下来,我们包括org。drools:drools-core工件,其中包含drools规则
引擎的实现。
最后,我们将包括org.drools:drools-compiler工件包含算法翻译规则写在不同的资源
(文本文件、电子表格、自己的类型,等等)来执行规则。这个工件是必需的,只是因为我们在项目的编译我们的规则。是有可能的单独的规则编译规则执行删除这种依赖性从我们的项目,但是,为了简单起见,我们将编译我们的规则在同一个项目
2、配置文件
src/main/resources
META-INF
kmodule.xml 定义 kieBase , kieSession ...
beans.xml cdi配置用
***.drl
....drl
二、规则语言
agenda-group "B to C" 规则组,默认是主组,可以使用auto-focus true来指定可以从主进到该组(允许对多个规则设置auto-focus true,这样应该是按优先级来了),也可以使用drools.getKnowledgeRuntime().getAgenda().getAgendaGroup( "B to D" ).setFocus(); 进入对应组
insertLogical 使对象驻留在工作内存中,直到插入他的条件不再为true
1、update($*);
或
modify($*){
setCategory(Category.LOW_RANGE)
}
可重新触发所有rule,而 $*.setCategory(Category.LOW_RANGE); 不会重新触发,继续触发能触发的rule
2、insert(new Coupon($c, $o, Coupon.CouponType.POINTS));
3、delete($cp);
4、salience 10 rule执行顺序,默认0可以负,越大越优先,条件可动态 salience($i.getCost())
5、no-loop 一次触发,在一次fireAll 中,只触发一次,哪怕中途 insert 了符合的条件
只能起作用于自身规则引起的触发,其他规则引起的触发还是会触发一次
可用 lock-on-active true
6、lock-on-active true 再次触发也忽略
6、global org.drools.devguide.eshop.service.EShopConfigService configService;
enabled (configService.isMidHighCategoryEnabled())
ksession.setGlobal("configService", mockService);
7、enabled 是否需要触发该rule,enabled (动态条件)
8、date-effective "01-Jan-2015" 规则生效时间
date-expires "31-Dec-2020" 截止时间
9、calendars "weekdays"
timer (int:0 1h) timer (cron:0 0 0/8 * * ?)
循环控制
10、Declared types
declare SpecialOrder extends Order
whatsSoSpecialAboutIt: String
order: Order
applicableDiscount: Discount
end
参考 chapter-04-tests DeclaredTypesTest.java
11、Property-reactive beans
类似no-loop lock-on-active 的控制能力,可更细粒度,如只对某个或一些变量的变化进行关注或不关注
参考 chapter-04-tests PropertyReactiveTest.java
特殊操作符
12、正则表达式
when $c: Customer(email not matches "[A-Za-z0-9-.]+@[A-Za-z0-9-.]+$")
then $c.setEmail(null); //invalidate email
13、集合 contains 、 memberOf
when
$i: Item(name == "pencil")
$ol: OrderLine(item == $i)
$o: Order($ol memberOf orderLines,orderLines contains $ol)
then ...
14、from 字句 when
Order(totalItems > 10, $c:customer)
Coupon(customer == $c) from qServ.queryCoupons()
then ...
15、Collect from objects 需要导入集合类,如 import java.util.List | Set
加入有50个Order在session中,将会触发50次,因此可用该方式触发一次
when
$list: List() from collect(Order()) | $list: List(size > 0) from collect(Order()) 收集到的结果数>0才触发
then
System.out.println("we've found " + $list.size() + " orders");
16、accumulate 积累 条件表达式
when
$o: Order($lines: orderLines)
Number(intValue >= 10) from accumulate( //String(toString contains '10') from accumulate( 可任意结果比较
OrderLine(
item.salePrice > 20.00,
$q: quantity
) from $lines,
init(int count = 0;),
action(count += $q;),
reverse(count -= $q;),
result(count)
//或直接使用 sum($q)
)
then
$o.increaseDiscount(0.05);
init 初始化方法
action 执行
reverse (可选)
result 结果
也可直接使用以下函数:
count: sum: avg: min: max: collectList: collectSet(对象不重复):
推荐直接使用函数
when accumulate(Order($total: total),
$maximum: max($total),
$minimum: min($total),
$average: avg($total)
)
then //...
参考 chapter-04-tests AccumulateTest.java
17、关键字
not not(Order() or Item()) 没有Order或Item则不触发
exists exists(Order()) exists这个关键字,与Order()的区别是:即使Order有多个,也只触发一次,同样 forall
forall 通常与 exists 联合使用作为预检查
exists(Order())
forall(
Order()
Order(orderLines.size() > 0)
)
三、常用api
KieSession kSession
1、insert(Object obj)
2、getObjects(...)
四、架构
1、环境加载
例如加载classpath配置,通过 KieServices.newKieClasspathContainer(); 扫描加载配置,包括 kmodule.xml , ***.drl 等
2、主要接口
1)KieServices , 主要提供 创建 KieContainer 接口,如 KieServices.newKieClasspathContainer(); 创建classpath环境的 KieContainer
2)KieContainer ——* KieModule , 提供创建 KieSession 等主要接口
3)KieModule 定义配置,可包含子KieModule
<kbase name="rules.cp.discount">
<ksession name="rules.cp.discount.session" type="stateful"/>
</kbase>
4)KieBase 定义在 KieModule 中 , 也提供创建 KieSession 接口
5)KieSession 定义在 KieBase 中 , insert modify update 操纵接口 , stateful 可交互多次, stateless 只交互1次, 且需要用
StatelessKieSession statelessKieSession = kContainer.newStatelessKieSession("rules.simple.sl.discount");创建
五、最佳实践
1、要避免条件引起的死循环,如 when $i:Item(cost < 200) then dosome....;update($i);//cost 还是 <200