熟悉命理书的朋友都知道,书上计划都是一些条文组成的断语,从下表可以看到,命理大师们习惯描述什么条件,会出现什么样的情况,这样看起来是不是很像规则引擎的职能呢?于是我就想调研一下java相关的规则引擎,是否满足命理的灵活多变的需要。或许比搞些设计模式,纯手工编码要好维护得多吧.
先不着急自己搭建环境,先了解有哪些,他们是什么,他们能干什么,在哪些领域有所应用。
1 drool
Drools中文网,DROOLS(JBOSS RULES )具有一个易于访问企业策略、易于调整以及易于管理的开源业务规则引擎,符合业内标准,速度快、效率高。业务分析师或审核人员可以利用它轻松查看业务规则,从而检验是否已编码的规则执行了所需的业务规则。
1.1 规则引擎
从上面官网给出的定义,首先看看什么业务规则引擎。参考业务规则引擎,业务规则包括了条件和触发操作两部分内容。而引擎是事物内部的重要的运行机制,规则引擎即重点是解决规则如何描述,如何执行,如何监控等一系列问题。它这个定义描述的比较清楚
再看业务规则和规则引擎这篇文章,我们知道如何更好地构建规则,它包含的要素如下:
-
事实:对业务的真实描述
-
约束:满足什么条件才可以执行
-
动作触发规则:触发的动作是什么
-
推论:如果怎样,结果怎样
-
计算:业务计算
那么通过什么工具,来描述业务规则呢? -
决策表:以表格形式描述业务规则,一行一天规则,列表示条件,当条件满足,触发动作。这个跟我上面的图一样
-
决策树:将一组业务规则通过树形结构表示,每一个分支表示一条决策路径,描述推论的规程,叶子节点即结果或动作
-
规则语言:通过计算机语言描述规则
-
脚本:描述过程的业务逻辑,if——then——else。
1.2 开源的有哪些
查看oschina,开源的业务规则引擎真心不少。 -
aswan:陌陌开发的风控系统静态规则引擎,用python写的,momosecurity/aswan
,当然github上也有人用java重写,根据Aswan轻量级风控静态规则引擎 | WitAwards2019“年度开源项目”参评巡礼中描述,aswan的规则引擎是面向用户行为的分析,预置了名单型策略(黑白名单)、布尔型策略(用户的属性阈值控制)、时段频率控制型策略、限制用户数型策略,这个项目对我们命理规则帮助不大。 -
stepchain:没什么名气,一年也没有更新,忽略
-
RuleEngine:
-
URule:以 RETE 算法为基础,提供了商业PRO版本和开源版,这种情况就不考虑了。应该有坑。就跟mongo一样,频繁读写副本集模式就容易挂掉,还不知是什么原因。
-
Easy Rules:基于POJO的开发与注解的编程模型,有点意思,可以深入分析一下。
-
Aristotle:Ruby 语言开发,不看
-
JBoss BPM Suite:业务流程管理平台,跟我的需求不符。
-
JBoss BRMS:JBoss BRMS是用于业务规则管理和复杂事件处理的平台,对我来说太重了。映象中JBPM之前都是用来做OA工作流程的
-
JBoss OptaPlanner:OptaPlanner 是轻量级的,可嵌入的规划引擎
-
Tohu:资料太少,没有调查性
-
A2D:基于C#等,不看
-
Esper:Complex Event Processing,目的是让用户能够通过它提供的接口,构建一个用于处理复杂事件的应用程序。跟我的场景不匹配。
-
NRuleEngine:c#规则引擎,我是java、python系,这个不用看
-
Simple Rule Engine:基于 .NET 开发,这个也不用看
-
Hammurabi:Scala编写的,暂不看
-
OpenL Tablets:penl Tables 是一个开源的规则引擎,大部分规则都可以通过Excel编写,这个有点意思,规则引擎–Openl Tables快速入门,这个里面描述通过提供API访问业务规则,看起来还不错。
-
Interleave:基于 Web 的业务流程自动化应用,对我用不着。
-
Activiti:工作流,用于OA,对我用不着。
-
Intalio BPM:工作流,不适用我的场景
-
Prova:它的设计工作在分布式企业服务总线和OSGi环境,有些重,不看了。
-
JRuleEngine:网上有些跟Drools的材料,规则引擎 Drools与JRuleEngine,drools提供了JRuleEngine的一些额外的内容。
-
InfoSapient:没看到太多的介绍,不看
-
JEOPS:sourceforge最后更新是2015年,也没人下载,pass。
-
Mandarax:Mandarax规则引擎调研.ppt中描述不支持API JSR-94,采用的是基于反向推理,即归纳法,那也没什么可看的了。
-
JRules:被IBM收购,WebSphere ILOG JRules 规则引擎运行模式简介。功能很强大,还有个 Rule Studio 设计。
-
JLisa:sourceforge last update为2013年,不看
-
NxBRE:.NET平台,不看
-
OpenRules:规则知识库是Excel(Decision Tables)方式的,不支持把知识库放在数据库中。有点意思。
-
Drools Expert:Drools Expert 是 Drools 平台上的一个规则引擎
-
Jess:体积小,重量轻,并且是最快的规则引擎之一,Ilog、Drools、Jess规则引擎的Rule Language 对比,看看里面编写规则,实在不想细看,对我们的编码习惯差异太大,果断放弃。
-
Drools.NET :.NET 版的 Drools,不看
-
Drools:名气很大
-
Apache Camel :物联网中也要用到,可以深入
1.3 LHS和RHS
阅读Gitee 极速下载 / RuleEngine,提到了RuleEngine可以直接使用SQL语句来定义规则的LHS部分,也可以自定义执行体部分(RHS)。那么什么是LHS和RHS呢?阅读LHS和RHS理解,快速理解JavaScript 中的 LHS 和 RHS 查询,赋值操作的左边和右边,编译原理中有些用,一般我们用不着。
1.4 RETE算法
RETE算法简述 & 实践,Rete 是一种进行大量模式集合和大量对象集合间比较的高效方法,通过网络筛选的方法找出所有匹配各个模式的对象和规则,当初考研的时候自学过编译原理,刚开始看懂了,不过2个月就全忘了,这玩意太复杂,研究不过来,了解干什么就行了。
1.5 JSR-94规则
参见JAVA规则引擎JSR-94笔札,Java 规则引擎与其 API (JSR-94),
过去大部分的规则引擎开发并没有规范化,有其自有的 API,这使得其与外部程序交互集成不够灵活。转而使用另外一种产品时往往意味需要重写应用程序逻辑和 API 调用,代价较大。规则引擎工业中标准的缺乏成为令人关注的重要方面。2003 年 11 月定稿并于 2004 年 8 月最终发布的 JSR 94(Java 规则引擎 API)使得 Java 规则引擎的实现得以标准化。从这段描述就知道 JSR 94的意义了。
1.6 DSL
Domain Specified Language,领域专用语言
1.7 kie
Knowledge Is EveryThing,参见Drools从入门到精通之KIE
1.8 springboot整合
首先看pom.xml
,参考了半小时搞定,规则引擎Drools 集成 springboot 热加载
<version.drools>7.47.0.Final</version.drools>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>${version.drools}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>${version.drools}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
<version>${version.drools}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-templates</artifactId>
<version>${version.drools}</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>${version.drools}</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-spring</artifactId>
<version>${version.drools}</version>
</dependency>
2 Easy Rules
easy-rules-core,2020年5月还有更新。查看规则引擎 Easy Rules 使用实例(一),在easy Rules中规则提供了java和yml两种方式,将if else更加优雅的表达。不过看了他的示例代码,你可能觉得 增加了扩展性,也增加了编写复杂度。再看规则引擎 Easy Rules 使用实例(二中的建议初学者将业务逻辑写在java中,一类规则,当中可能就有很多的内部类。
使用easy rules的优先级不是可视化的,逻辑不是很直观。
另外针对八字命理,规则太多了,那是不是我要定义很多的规则类呢?而每个规则断语很多都是只有符合一些条件,才能怎样,没有说不符合,又会怎样。
参见Java规则引擎 Easy Rules
将我之前的代码调整为easy rules的模式,虽然我之前是在过滤器模式来做的,调整后感觉确实优雅多了,而且逻辑也非常清晰。
@Override
public void doFilter(BaZi bazi, List<QiangRuoAssertionDto> assertions, QiangRuoFilterChain chain) {
QiangRuoAssertionDto assertionDto = null;
if (WuXingUtil.isYinBi(bazi.getDayDiZhi().getWuXing(), bazi.getDayTianGan().getWuXing()) && bazi.getHourDiZhi()!=null
&& WuXingUtil.isYinBi(bazi.getHourDiZhi().getWuXing(), bazi.getDayTianGan().getWuXing())
&& !WuXingUtil.isYinBi(bazi.getYearDiZhi().getWuXing(), bazi.getDayTianGan().getWuXing())
&& !WuXingUtil.isYinBi(bazi.getMonthDiZhi().getWuXing(), bazi.getDayTianGan().getWuXing())){
if (bazi.getDayDiZhi().getWuXing() == bazi.getHourDiZhi().getWuXing()
&& WuXingUtil.isYin(bazi.getDayDiZhi().getWuXing(), bazi.getDayTianGan().getWuXing())){
// 日时双印
assertionDto = new QiangRuoAssertionDto();
assertionDto.setAssertion("日时双印,年月非根印,不论组合,不看天干,皆身弱论命");
assertionDto.setSection(SectionEnum.QIANG_RUO);
assertionDto.setQiangruo(QiangRuoEnum.RUO);
assertions.add(assertionDto);
} else{
if (TianGanUtil.yinBiYiPian(bazi) || TianGanUtil.ganTou(bazi.getDayGan().getZhengYin(),bazi)+TianGanUtil.ganTou(bazi.getDayGan().getBiJian().getWuXing(),bazi)>=2){
assertionDto = new QiangRuoAssertionDto();
assertionDto.setAssertion("根根、印根、根印在日时同时出现,天干印比一片,皆以旺论");
assertionDto.setSection(SectionEnum.QIANG_RUO);
assertionDto.setQiangruo(QiangRuoEnum.WANG);
assertions.add(assertionDto);
} else{
assertionDto = new QiangRuoAssertionDto();
assertionDto.setAssertion("根根、印根、根印在日时同时出现,年月时干有一处不是印比,以弱论,合化出的印比不能算!");
assertionDto.setSection(SectionEnum.QIANG_RUO);
assertionDto.setQiangruo(QiangRuoEnum.RUO);
assertions.add(assertionDto);
}
}
}
chain.doFilter(bazi, assertions, chain);
}
先看看pom.xml
中的配置
<version.easyrule>4.0.0</version.easyrule>
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-core</artifactId>
<version>${version.easyrule}</version>
</dependency>
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-support</artifactId>
<version>${version.easyrule}</version>
</dependency>
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-mvel</artifactId>
<version>${version.easyrule}</version>
</dependency>
接着是定义yml
# 生 1 克 2 助 3 泄 4 耗 5
# 印 1 官 2 比劫根 3 食伤 4 财 5
# 年月时天干印比一片 1,天干合化印比一片 2,有一处不是印比 0
---
name: "日时根印规则1"
description: "日时双印,年月非根印,不论组合,不看天干,皆身弱论命"
priority: 1
condition: "feature.yz!=1 && feature.yz!=3 && feature.mz!=1 && feature.mz!=3 && feature.dz==1 && feature.hz==1"
actions:
- "feature.setResult(\"弱\");"
---
name: "日时根印规则2"
description: "根根、印根、根印在日时同时出现,天干印比一片,皆以旺论"
priority: 2
condition: "feature.yz!=1 && feature.yz!=3 && feature.mz!=1 && feature.mz!=3 && ((feature.dz==1 && feature.hz==3) || (feature.dz==3 && feature.hz==3) ||(feature.dz==3 && feature.hz==1)) && feature.ymhg==1"
actions:
- "feature.setResult(\"旺\");"
---
name: "日时根印规则3"
description: "根根、印根、根印在日时同时出现,年月时干有一处不是印比,以弱论,合化出的印比不能算!"
priority: 3
condition: "feature.yz!=1 && feature.yz!=3 && feature.mz!=1 && feature.mz!=3 && ((feature.dz==1 && feature.hz==3) || (feature.dz==3 && feature.hz==3) || (feature.dz==3 && feature.hz==1)) && feature.ymhg==0"
actions:
- "feature.setResult(\"弱\");"
easy-rules mvel yaml 格式规则配置&&试用二——rule 数据返回结果,从这篇文章中我知道了我们需要定义一个顶级的规则,才好拿到easy rules的返回值,也算是一种折中的办法,不过没有成功。Easy Rules core包 规则引擎这篇文章讲的比较细致。不过到返回值的时候,感觉哪些示例都是在过家家,我要哪些system.out.print
有啥用呢?
第一个对象,用于传值和接受返回值
package com.dzmsoft.bazi.dto;
public class BaziFeatureDto {
private Integer yz;
private Integer mz;
private Integer dz;
private Integer hz;
private Integer ymhg;
private String result;
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
public Integer getYz() {
return yz;
}
public void setYz(Integer yz) {
this.yz = yz;
}
public Integer getMz() {
return mz;
}
public void setMz(Integer mz) {
this.mz = mz;
}
public Integer getDz() {
return dz;
}
public void setDz(Integer dz) {
this.dz = dz;
}
public Integer getHz() {
return hz;
}
public void setHz(Integer hz) {
this.hz = hz;
}
public Integer getYmhg() {
return ymhg;
}
public void setYmhg(Integer ymhg) {
this.ymhg = ymhg;
}
}
然后是调用的测试验证,skipOnFirstFailedRule
这个并不是什么的时候都可以设置的
package com.dzmsoft.bazi.rule.qiangruo.shy;
import com.dzmsoft.bazi.dto.BaziFeatureDto;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.api.RulesEngineParameters;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.jeasy.rules.mvel.MVELRuleFactory;
import org.jeasy.rules.support.reader.YamlRuleDefinitionReader;
import java.io.FileReader;
public class Test {
public static void main(String[] args) throws Exception {
RulesEngineParameters parameters = new RulesEngineParameters()
.skipOnFirstAppliedRule(true)
// .skipOnFirstFailedRule(true)
// .skipOnFirstNonTriggeredRule(true)
;
RulesEngine rulesEngine = new DefaultRulesEngine(parameters);
MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());
String fileName = Test.class.getClassLoader().getResource("shy32.yml").getFile();
System.out.println(fileName);
Rules rules = ruleFactory.createRules(new FileReader(fileName));
BaziFeatureDto baziFeatureDto = new BaziFeatureDto();
baziFeatureDto.setYz(2);
baziFeatureDto.setMz(2);
baziFeatureDto.setDz(1);
baziFeatureDto.setHz(3);
baziFeatureDto.setYmhg(0);
Facts facts = new Facts();
facts.put("feature",baziFeatureDto);
rulesEngine.fire(rules,facts);
System.out.println(baziFeatureDto.getResult());
}
}
3 OptaPlanner
OptaPlanner逐步学习(0) : 基本概念 - OptaPlanner,规划问题, 约束,方案,OptaPlanner是一个对待规划的方案组合进行优化的引擎。规划问题是 - 基于有限资源,及指定约束条件下达到优化目标(包括资源、排程安排等优化)。比如最大化利润、最小化影响,有点像运筹学里面的内容。现阶段没有这方面的要求,这哪是搁置。不过感觉这个应该蛮有用。
4 Apache Camel
Apache Camel系列(1)----使用场景,从这篇文章可以知Apache Camel是一个基于Enterprise Integration Pattern(企业整合模式,简称EIP)的开源框架,可以解决不同的应用系统之间以不同的方式传递消息
4.1 Akka
为什么Akka(Actor模型)在中国不温不火?
,但Flink通过Akka实现的分布式通信。
4.2 Actor模型
十分钟理解Actor模式,MapReduce就是一种典型的Actor模式,Actor模型share nothing,与共享内存型相反,共享内存更适合单机多核的并发编程。而单机多核并发编程就需要注意锁和内存原子性等一系列线程问题,看起来了Actor模式更简单。
4.3 EIP
Enterprise Integration Patterns 企业集成模式(EIP),什么时候使用Apache camel