参考
https://www.yiibai.com/drools/drools_eclipse_plugin.html#article-start
https://www.cnblogs.com/yjmyzz/p/drools-tutorial.html
http://www.ityouknow.com/drools/2017/08/07/drools-started.html
规则引擎
规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据业务规则做出业务决策。
java开源的规则引擎有:Drools、Easy Rules、Mandarax、IBM ILOG。使用最为广泛并且开源的是Drools。
Drools
Drools 是一个基于Charles Forgy’s的RETE算法的,易于访问企业策略、易于调整以及易于管理的开源业务规则引擎,符合业内标准,速度快、效率高。 业务分析师人员或审核人员可以利用它轻松查看业务规则,从而检验是否已编码的规则执行了所需的业务规则。
Drools 是用Java语言编写的开放源码规则引擎,使用Rete算法对所编写的规则求值。Drools允许使用声明方式表达业务逻辑。可以使用非XML的本地语言编写规则,从而便于学习和理解。并且,还可以将Java代码直接嵌入到规则文件中,这令Drools的学习更加吸引人。
rate算法参考:https://developer.ibm.com/zh/articles/os-drools/
- Drools相关概念:
事实(Fact):对象之间及对象属性之间的关系
规则(rule):是由条件和结论构成的推理语句,一般表示为if…Then。一个规则的if部分称为LHS,then部分称为RHS。
模式(module):就是指IF语句的条件。这里IF条件可能是有几个更小的条件组成的大条件。模式就是指的不能在继续分割下去的最小的原子条件。
环境部署
下面是安装Drools插件的先决条件:
- Java1.5(以上) SE JDK:Eclipse 4.2或者InterJ都可以自动集成JDK
- Drools插件
插件安装方法:https://www.yiibai.com/drools/drools_eclipse_plugin.html#article-start
如何运行
规则引擎就是避免每次手动修改if else的逻辑分支,通过规则引擎吧UI展示与代码解耦。
解耦后通过规则文件描述符合什么条件的时候,应该去做什么事情;每当规则有变动的时候,只需要修改规则文件,然后重新加载即可生效。
规则文件--drl
drools有专门的规则语法drl,就是专门描述活动的规则是如何执行的
package rules
import com.neo.drools.entity.Order
rule "zero"
no-loop true
lock-on-active true
salience 1
when
$s : Order(amout <= 100)
then
$s.setScore(0);
update($s);
end
rule "add100"
no-loop true
lock-on-active true
salience 1
when
$s : Order(amout > 100 && amout <= 500)
then
$s.setScore(100);
update($s);
end
rule "add500"
no-loop true
lock-on-active true
salience 1
when
$s : Order(amout > 500 && amout <= 1000)
then
$s.setScore(500);
update($s);
end
rule "add1000"
no-loop true
lock-on-active true
salience 1
when
$s : Order(amout > 1000)
then
$s.setScore(1000);
update($s);
end
关键词规则
- package 与Java语言类似,drl的头部需要有package和import的声明,package不必和物理路径一致。
- import 导出java Bean的完整路径,也可以将Java静态方法导入调用。
要应用规则的任何fact,这些fact都需要导入。例如,com.sample.DroolsTest.Message; 在上面的例子。 - rule 规则名称,需要保持唯一 件,可以无限次执行。
- no-loop 定义当前的规则是否不允许多次循环执行,默认是 false,也就是当前的规则只要满足条件,可以无限次执行。
- lock-on-active 将lock-on-active属性的值设置为true,可避免因某些Fact对象被修改而使已经执行过的规则再次被激活执行。
- salience 用来设置规则执行的优先级,salience 属性的值是一个数字,数字越大执行优先级越高, 同时它的值可以是一个负数。默认情况下,规则的 salience 默认值为 0。如果不设置规则的 salience 属性,那么执行顺序是随机的。
- when 条件语句,就是当到达什么条件的时候
- then 根据条件的结果,来执行什么动作
- end 规则结束
语法
- 条件:== 等于
- 变量:以美元($)符号开始
- 注释:
//或#,标记单行注释
/* XXX */ 多行注释
等等:https://www.yiibai.com/drools/drools_rule_syntax.html#article-start
全局调度--配置文件kmodule.xml
这里需要有一个配置文件告诉代码规则文件drl在哪里,在drools中这个文件就是kmodule.xml,放置到resources/META-INF目录下。
kmodule.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.drools.org/xsd/kmodule">
<kbase name="point-rulesKB" packages="rules">
<ksession name="point-rulesKS"/>
</kbase>
</kmodule>
对配置文件进行说明:
- Kmodule 中可以包含一个到多个 kbase,分别对应 drl 的规则文件。
- Kbase 需要一个唯一的 name,可以取任意字符串。
- packages 为drl文件所在resource目录下的路径。注意区分drl文件中的package与此处的package不一定相同。多个包用逗号分隔。默认情况下会扫描 resources目录下所有(包含子目录)规则文件。
- kbase的default属性,标示当前KieBase是不是默认的,如果是默认的则不用名称 就可以查找到该 KieBase,但每个 module 最多只能有一个默认 KieBase。
- kbase 下面可以有一个或多个 ksession,ksession 的 name 属性必须设置,且必须唯一。
前端处理
代码如下
public static final void main(final String[] args) throws Exception{
KieServices ks = KieServices.Factory.get();
KieContainer kc = ks.getKieClasspathContainer();
execute( kc );
}
public static void execute( KieContainer kc ) throws Exception{
KieSession ksession = kc.newKieSession("point-rulesKS");
List<Order> orderList = getInitData();
for (int i = 0; i < orderList.size(); i++) {
Order o = orderList.get(i);
ksession.insert(o);
ksession.fireAllRules();
addScore(o);
}
ksession.dispose();
}
代码解释:首先通过请求获取 KieServices,通过KieServices获取KieContainer,KieContainer加载规则文件并获取KieSession,KieSession来执行规则引擎,KieSession是一个轻量级组建,每次执行完销毁。KieContainer是重量级组建可以考虑复用。
应用拓展
excel生成规则
下面来解释一下每一行都什么意思
表示规则属于哪个包下的,类似于java中的 package
规则在处理逻辑时用到的类,多个的话,在后面用逗号隔开
一些共用方法可以通过 Functions 来定义,跟java中的方法差不多,就是把 public 换成了 function
空行,必须要有的
给这个excel里的规则定义一个名字,方便别人查看
从这一行开始下面就是规则的部分了,这一行相当于表头,标注了每一列都是什么意思,固定写法,其中 CONDITION 可以有多个
这一行是初始化对象的
指定条件以及输出的处理方式
这一行开始就是真实的业务逻辑了,CONDITION 下的是条件,ACTION 下的是结果,我这给这一行也定成了表头并起了相应的名字,如果不想定表头的话,这一行要为空行
第一列是规则名,第二列是条件,第三列是结果
读取Excel生成规则文件
//把excel翻译成drl文件
@Test
public void test2() {
SpreadsheetCompiler compiler = new SpreadsheetCompiler();
// 最后一个参数是excel里 sheet 的名称
String rules = compiler.compile(ResourceFactory.newClassPathResource("rules" + File.separator + "rule.xlsx", "UTF-8"), "Sheet1");
try {
BufferedWriter out = new BufferedWriter(new FileWriter("src/main/resources/rules/test-rule-excel.drl"));
out.write(rules);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
上面excel里的规则生成的文件内容如下
package com.example.demo;
//generated from Decision Table
import com.example.drools.Demo;
function int count(Demo $demo) {
return $demo.getA() + $demo.getB() + $demo.getC();
}
// rule values at A10, header at A5
rule "条件计算1"
when
$demo:Demo(a>3,b>4)
then
$demo.setTotal(count($demo));
end
// rule values at A11, header at A5
rule "条件计算2"
when
$demo:Demo(c<3)
then
$demo.setTotal($demo.getA() + $demo.getB());
end
直接读取Excel决策表处理业务规则
上面介绍了读取excel生成rule文件,然后再通过读取规则文件来处理业务,这样比较麻烦,下面来介绍一下直接读取excel,然后处理业务逻辑
代码如下
//读取excel规则处理逻辑
@Test
public void test1() {
KieServices kieServices = KieServices.Factory.get();
Resource dt = ResourceFactory.newClassPathResource("rules/rule.xlsx", getClass());
KieFileSystem kieFileSystem = kieServices.newKieFileSystem().write(dt);
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
kieBuilder.buildAll();
KieModule kieModule = kieBuilder.getKieModule();
KieSession kieSession = kieServices.newKieContainer(kieModule.getReleaseId()).newKieSession();
Demo demo = new Demo();
demo.setA(6);
demo.setB(5);
demo.setC(4);
kieSession.insert(demo);
int count = kieSession.fireAllRules();
System.out.println("总共触发了: " + count + " 条规则");
System.out.println(demo);
}
总共触发了: 1 条规则
Demo{a=6, b=5, c=4, total=15, errorMsg=[]}
总结
jboss还提供了一个网站,能直接在网页上配置出来规则,更加方便了,不过对于程序员来说,写drl文件应该是首选,对于业务人员写excel应该是首选
PHP与规则引擎
php没有太多的经典规则引擎,可以参考https://github.com/tonera/Rules