调研规则引擎用于八字命理中介绍了easyrules,easyrules比较轻量,但实际使用规则引擎,还是drools更能胜任复杂的业务。因为决策表可以让这个逻辑更加优雅
为什么一定要研究规则引擎,因为边缘计算中规则引擎是一个技术趋势,但是drools在边缘中运行就有些重了。当你看了很多命理书的时候,感觉还是用规则引擎来做,比使用java设计模式要强的多。
我的目的是八字命理,并不想把kie-spring再来一遍,于是就使用到fast-drools-spring-boot-starter这个插件
<properties>
<version.fast-drools>8.0.7</version.fast-drools>
<version.lombok>1.16.14</version.lombok>
<version.spring-cloud>2.0.1.RELEASE</version.spring-cloud>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>com.github.hongwen1993</groupId>
<artifactId>fast-drools-spring-boot-starter</artifactId>
<version>${version.fast-drools}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${version.lombok}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>${version.spring-cloud}</version>
</dependency>
</dependencies>
1 决策表
出现下面的错误是因为dto这个对象没有解析到,这里主要dto的位置要填写那个格,按照上图说明
2021-02-27 16:53:56.160 ERROR 1824 --- [pool-1-thread-1] com.drools.core.KieTemplate : file not fount.
2021-02-27 16:53:56.478 WARN 1824 --- [ main] o.d.c.kie.builder.impl.KieBuilderImpl : File 'file0.drl' is in folder '' but declares package 'com.dzmsoft.qingqiu'. It is advised to have a correspondance between package and folder names.
2021-02-27 16:53:57.269 ERROR 1824 --- [ main] o.d.c.kie.builder.impl.KieProject : Unable to build KieBaseModel:defaultKieBase
Predicate 'dto.setResult("旺")' must be a Boolean expression
编译出了错误,这个时候就可以参照Drools决策表的使用将决策表转化为drl查看发生了什么
import org.drools.decisiontable.InputType;
import org.drools.decisiontable.SpreadsheetCompiler;
@Test
public void test02() throws FileNotFoundException {
File file = new File("F:\\bazi_rules\\shy.xlsx");
InputStream is = new FileInputStream(file);
SpreadsheetCompiler compiler = new SpreadsheetCompiler();
String drl = compiler.compile(is, InputType.XLS);
System.out.println(drl);
}
下面有两个地方有异常,
① dto.setResult(旺)
说明ACTION应该写成dto.setResult("$1");
,加上引号
② when条件不正确,故提示then这个错误。第二个condition没有解析,解决方案是引用同一个对象的condition合并为一个单位格,赋值dto:ShyGenYinDto
package com.dzmsoft.qingqiu.rule;
//generated from Decision Table
import com.dzmsoft.qingqiu.rule.dto.ShyGenYinDto;
import java.lang.Integer;
import java.lang.String;
// rule values at B8, header at B3
rule "根根在年支、月支"
when
dto:ShyGenYinDto(yz == "助")
mz
then
dto.setResult(旺);
end
// rule values at B9, header at B3
rule "根印在年支、月支"
when
dto:ShyGenYinDto(yz == "助")
mz
then
dto.setResult(旺);
2021-02-27 17:10:09.325 ERROR 8744 --- [pool-1-thread-1] com.drools.core.KieTemplate : file not fount.
2021-02-27 17:10:09.634 WARN 8744 --- [ main] o.d.c.kie.builder.impl.KieBuilderImpl : File 'file0.drl' is in folder '' but declares package 'com.dzmsoft.qingqiu'. It is advised to have a correspondance between package and folder names.
2021-02-27 17:10:09.729 ERROR 8744 --- [ main] o.d.c.kie.builder.impl.KieProject : Unable to build KieBaseModel:defaultKieBase
[11,1]: [ERR 102] Line 11:1 mismatched input 'then' in rule "根根在年支、月支"
正确的决策表生成规则是这样的了
rule "根根在年支、月支"
when
dto:ShyGenYinDto(yz == "助", mz == "助")
then
dto.setResult("旺");
end
可以看到决策表中如果出现tgbqcn>=Integer.valueOf($1) and tgbqcn<=Integer.valueOf($2)
,生成drl的时候就出现问题了,解决方案也比较简单,采用tgbqcn>=Integer.valueOf($1) , tgbqcn<=Integer.valueOf($2)
,用逗号代替and就可以了
rule "月支根,年支、日支克月支,根本气透干2个以上"
when
dto:ShyGenYinDto(yz == "克", mz == "助", dz == "克", bqtg == "是", tgbqcn>=Integer.valueOf(2) and tgbqcn<=Integer.valueOf(3))
then
dto.setResult("弱");
end
这里再思考一个问题,决策表的规则那么多,它们之间怎么样保证互斥关系的呢?就好比我的实验,发现实施效果并不理想。
为防止冲突,增加了两个配置ACTIVATION-GROUP
对规则进行分组和Sequential
设置为顺序执行,设置好后,发现还是不行
将决策表生成的规则,写入到drl文件中,进行调试。
原则上根根在年支、时支,天干不是印比一片(包括合化)
的salience要高于年支根,月支泄根一次,本气透干
为什么,匹配到后者呢?
activation-group设置的一组规则,只需要一个执行,其他的就不执行了,相当于组内的规则是互斥的。那么只要年支根,月支泄根一次,本气透干
的activation-group
为2,同一个规则,就可以匹配到正确的了。
但是不同activation-group之间的呢?并不影响。
agenda-group是同一组的规则都会执行。
package com.dzmsoft.qingqiu.rules;
//generated from Decision Table
import com.dzmsoft.qingqiu.rules.dto.ShyGenYinDto;
import java.lang.Integer;
// rules values at B90, header at B4
rule "根根在年支、时支,天干印比一片"
salience 65454
activation-group "2"
when
dto:ShyGenYinDto(yz == "助", hz == "助", tgybyp == "1")
then
dto.setResult("旺");
dto.setDesc("根根在年支、时支,天干印比一片");
end
// rules values at B91, header at B4
rule "根根在年支、时支,天干合化印比一片"
salience 65453
activation-group "2"
when
dto:ShyGenYinDto(yz == "助", hz == "助", tghhybyp == "1")
then
dto.setResult("旺");
dto.setDesc("根根在年支、时支,天干合化印比一片");
end
// rules values at B92, header at B4
rule "根根在年支、时支,天干不是印比一片(包括合化)"
salience 65452
activation-group "2"
when
dto:ShyGenYinDto(yz == "助", hz == "助", tghhybyp == "0", tgybyp == "0")
then
dto.setResult("弱");
dto.setDesc("根根在年支、时支,天干不是印比一片(包括合化)");
end
rule "年支根,月支泄根一次,本气透干"
salience 65439
activation-group "4"
when
dto:ShyGenYinDto(yz == "助", mz == "泄", bqtg == "1")
then
dto.setResult("弱");
dto.setDesc("年支根,月支泄根一次,本气透干");
end
// rule values at B106, header at B4
rule "年支根,月支泄根一次,合化本气透干"
salience 65438
activation-group "4"
when
dto:ShyGenYinDto(yz == "助", mz == "泄", hhbqtg == "1")
then
dto.setResult("弱");
dto.setDesc("年支根,月支泄根一次,合化本气透干");
end
解决规则冲突,另外的办法,就是就规则设置更加清晰,问题也就能解决。比如把某些规则的值设置的更加清晰一些