代码地址 https://github.com/tothis/java-record/tree/main/decision-table

Drools 决策表运行太慢暂无解决方法,遂决定使用自定义 Groovy 执行表达式作为规则引擎。

build.gradle.kts

plugins {java
}group = "com.example"
version = "0.0.1-SNAPSHOT"repositories {mavenCentral()
}dependencies {// CSVimplementation("org.apache.commons:commons-csv:1.9.0")// Groovyimplementation("org.codehaus.groovy:groovy:3.0.9")testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}tasks.getByName<Test>("test") {useJUnitPlatform()
}

user-level.csv

,condition,condition,condition,
,o.age > %s,o.age <= %s,o.sex == %s,o.level = %s
,年龄上限,年龄下限,性别,等级
男性高等级,0,10,0,2
女性高等级,0,15,1,2
男性中等级,10,15,0,1
女性中等级,15,20,1,1
低等级,,,,0

DecisionTableUtil.java

package com.example;import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVRecord;import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** 决策表工具*/
public final class DecisionTableUtil {private static final Map<String, Class<?>> CACHE_CLASS = new ConcurrentHashMap<>();private static final String FRAME = "def call(%s o){%s}";/*** 上方固定行* 1:注释行*/private static final int TOP_NUMBER = 1;/*** 左侧固定行* 1:注释行*/private static final int LEFT_NUMBER = 1;public static void call(final String fileName, final Object v) {final String className = v.getClass().getName();final Class<?> clazz;final GroovyObject obj;try {if (CACHE_CLASS.containsKey(fileName)) {clazz = CACHE_CLASS.get(fileName);} else {clazz = new GroovyClassLoader().parseClass(String.format(FRAME, className, buildScript(fileName)));CACHE_CLASS.put(fileName, clazz);}obj = (GroovyObject) clazz.getDeclaredConstructor().newInstance();} catch (final Exception e) {throw new RuntimeException(e);}obj.invokeMethod("call", v);}private static StringBuilder buildScript(final String fileName) throws IOException {final ClassLoader loader = DecisionTableUtil.class.getClassLoader();final FileReader reader = new FileReader(loader.getResource(fileName).getFile());final List<CSVRecord> rows = CSVFormat.INFORMIX_UNLOAD_CSV.parse(reader).getRecords();final CSVRecord head = rows.get(0);// 条件索引int conditionIndex = LEFT_NUMBER;for (; conditionIndex < head.size(); conditionIndex++) {if (!head.get(conditionIndex).equals("condition")) {break;}}// 表达式final CSVRecord expression = rows.get(1);final StringBuilder script = new StringBuilder();// 条件StringBuilder condition;// 动作StringBuilder action;for (int i = 2 + TOP_NUMBER; i < rows.size(); i++) {// 条件condition = new StringBuilder();// 第一组条件if (i == 2 + TOP_NUMBER) {condition.append("if(");} else {condition.append("else if(");}final CSVRecord row = rows.get(i);// 是否无条件boolean conditionFlag = true;for (int j = LEFT_NUMBER; j < conditionIndex; j++) {final String rowItem = row.get(j);// 过滤有效行if (!rowItem.equals("")) {condition.append(String.format(expression.get(j), rowItem)).append("&&");conditionFlag = false;}}if (conditionFlag) {// 删除最后的 ` if(` 字符串condition.delete(condition.length() - 4, condition.length());script.append(condition).append("{");} else {// 删除最后的 `&&` 字符串condition.delete(condition.length() - 2, condition.length());script.append(condition).append("){");}// 动作action = new StringBuilder();for (int j = conditionIndex; j < row.size(); j++) {final String rowItem = row.get(j);// 过滤无效值if (!rowItem.equals("")) {action.append(String.format(expression.get(j), rowItem.trim())).append('\n');}}script.append(action).append("}");}return script;}
}

DecisionTableUtilTest.java

package com.example;import org.junit.jupiter.api.Test;import static com.example.DecisionTableUtil.call;
import static org.junit.jupiter.api.Assertions.assertEquals;public final class DecisionTableUtilTest {@Testpublic void test() {class UserLevel {public Integer level;private Integer age;private Integer sex;public void setAge(final Integer age) {this.age = age;}public void setSex(final Integer sex) {this.sex = sex;}public Integer getLevel() {return level;}}final UserLevel v = new UserLevel();v.setSex(0);v.setAge(10);call("user-level.csv", v);assertEquals(v.getLevel(), 2);v.setSex(1);v.setAge(20);call("user-level.csv", v);assertEquals(v.getLevel(), 1);v.setAge(30);call("user-level.csv", v);assertEquals(v.getLevel(), 0);}
}

仿 Drools 决策表 Groovy 实现相关推荐

  1. drools 决策表_骆驼和春天的Drools决策表

    drools 决策表 正如我在之前的文章中所展示的那样, JBoss Drools是一个非常有用的规则引擎 . 唯一的问题是,对于非技术人员而言,以Rule语言创建规则可能会非常复杂. 这就是为什么人 ...

  2. 骆驼和春天的Drools决策表

    正如我在之前的文章中所展示的那样, JBoss Drools是一个非常有用的规则引擎 . 唯一的问题是,对于非技术人员而言,以Rule语言创建规则可能会非常复杂. 这就是为什么可以提供一种轻松的方式来 ...

  3. Drools决策表+SpringBoot使用及语法详解

    SpringBoot+Drools决策表的使用 简介 Drools决策表 决策表部分关键字 规则部分关键字 总结 SpringBoot 项目中决策表的使用 pom配置 验证决策表格式是否正确 利用Ki ...

  4. jboss drools_JBoss Drools –入门

    jboss drools 这篇文章是关于我如何掌握JBoss Drools的 . 其背后的原因是:SAP收购了我公司当前的规则引擎,而Drools是我们将寻找的另一种选择,只要有人有能力提高概念验证的 ...

  5. JBoss Drools –入门

    这篇文章是关于我如何掌握JBoss Drools的 . 其背后的原因是:SAP收购了我公司当前的规则引擎,而Drools是我们将寻找的另一种选择,只要有人掌握了概念验证的技能即可. 尽管似乎有大量的文 ...

  6. drools6.3+spring+Drools Workbench+activemq搭建风险控制系统

    根据业务的需求,从2015年10月份开始模式搭建一个风险控制系统,用于对实时交易的实时控制和非实时监控.当时上网搜索了一下,发现一个不错的框架drools,然后耗费了三个月,终于把drools引入到风 ...

  7. 八字命理应用drools规则引擎

    调研规则引擎用于八字命理中介绍了easyrules,easyrules比较轻量,但实际使用规则引擎,还是drools更能胜任复杂的业务.因为决策表可以让这个逻辑更加优雅 为什么一定要研究规则引擎,因为 ...

  8. 规则引擎 drools_网易考拉规则引擎平台架构设计与实践

    背景 考拉安全部技术这块目前主要负责两块业务:一个是内审,主要是通过敏感日志管理平台搜集考拉所有后台系统的操作日志,数据导入到es后,结合storm进行实时计算,主要有行为查询.数据监控.事件追溯.风 ...

  9. 互联网风控系统架构分析

    本文简单介绍风控具体是做什么的,以及一些常见的风控系统实现的架构. 文章目录 前言 一.互联网风控是做什么的? 风控的定义 二.常见风控系统的实现架构 1.风控系统的架构 2.风控的系统流程 三.核心 ...

  10. 网易考拉规则引擎平台架构设计与实践

    此文已由作者肖凡授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 背景 考拉安全部技术这块目前主要负责两块业务:一个是内审,主要是通过敏感日志管理平台搜集考拉所有后台系统的操作 ...

最新文章

  1. 服务模拟-ServiceMock
  2. AngularJS从子控制器访问父作用域
  3. python 报错 bs4 FeatureNotFound: Couldn‘t find a tree builder with the features you requested: lxml
  4. D - Bear and Finding Criminals
  5. 2017暑假 第四周 学习总结(复习)
  6. 黄东旭:Cloud-Native 的分布式数据库架构与实践
  7. 使用sysbench对mysql压力测试
  8. java.sql.SQLException: The server time zone value ‘???ú±ê×??±??‘ is unrecognized or represents more
  9. Python 3.5 正式退役,不再受支持
  10. Mybatis根据IdType生成不同类型的主键id
  11. VRRP技术原理与注意点
  12. paip. java的 函数式编程 大法
  13. OracleLinux6的安装
  14. 深度学习框架PyTorch:入门与实践 学习(三)
  15. Postman:脚本应用_pm对象
  16. C C++实现网络验证和本地验证
  17. ardupilot 关于设备车Rover的学习《1》------如何编译下载
  18. CleanMyMac4.13最新免费mac电脑系统优化软件
  19. 【情人节特别篇】想知道玫瑰在哪些城市最畅销嘛?
  20. TDD双工方式保护时隙与通信距离的关系

热门文章

  1. 【模拟】桐桐的新闻系统
  2. 自己做的js甘特图插件
  3. 打工就是 “演戏”,你可以认真,但别太当真
  4. STM8新建IAR工程
  5. ShinyApp中的表格:第三天笔记
  6. Windows利用系统自带的Dism命令挂载wim文件
  7. 大数据风控---风险量化和风险定价
  8. matlab(slove)如何应用,README.md/matlab/slove at master · SeanXP/README.md · GitHub
  9. 横版闯关手游【觉醒大陆90装备版】5月最新整理商业Linux手工服务端+吃鸡+组队PK+运营后台+CDK清包后台+GM授权后台+安卓苹果双端+视频教程+详细搭建教程
  10. 数据结构名次计算和排序算法