• 非全自研可视化表达引擎-RuleLinK



     说在前面

    工作中经常会遇到这样的场景:

    •  帮忙把小贝拉门店 商品金额在5w以内,产康订单最多95折。

    • 帮忙把圣贝拉门店 开业时间在6个月内,折扣低于7折要发起审批

    • 帮忙把宁波太平洋店设置独立合同模板

    • 帮忙把节假日成本变成1000

    • ...

    有些三五月变一次,有些一月变一次,有些一周变几次,每次修改都是去巴拉代码,不胜其烦。

    系统中的规则分散在各各PRD,有些人脑袋里也存了一份,但是随着人员的迭代,需求的迭代,最新永远散落在各初的代码中。这会带来诸多问题:

    • 学习成本高

    • 维护成本高

    • 开发成本高

    • 测试成本高

    于是有了创建一个规则的管理与运营平台,以及支撑规则的解释与执行的框架的想法。用以消除样板式代码,解放生产力,让规则的变化变得的简单。

     

    RuleLink的定位

    RuleLink是一款可视化表达式引擎。致力于解决业务开发过程中,规则变化成本高, 规则管理分散,维护成本高,学习成本高,大量样板式代码等一系列的问题。

    RuleLink名称的由来

    用规则连接业务逻辑,让研发专注业务逻辑,让规则的配置变得的简单。

    RuleLink 是基于 Aviatorscript  实现 规则的解析,基于开源项目 "rule-engine-builder-ui"实现表达式生成与渲染。(我只是代码搬运工,所以取名非全自研)

    基于当下我们的业务规则量,RuleLink并未使用性能更好的 Rete算法,而是使用了传统的模式匹配。

     

    为什么要建RuleLink

    除了前面介绍的之外,另一个原因则是想弥补一下上一份的工作中的一点点小遗憾。

    可视化表达式引擎的建设有两个难点:

    1. 表达式的解释与执行

    2. 表达式的生成与解析

    第1点相对简单,于是在1月份时,捣鼓了一些基础代码,做了一些尝试,当时还因为部署Drools 的workbench 搞得停服20分钟,拿了人生第一C绩效。

    到4月份接到这样一个需求,某业务线不同订单订单需要接不同的聚合支付账号。因为原来就换过一次了,为了支持快速切换,我们开始在Q1的代码基础做了一些调整,开始有了RuleLink的雏形。后来又陆续接入了一些场景:

    • 新业务支付支持不同主体

    • 订单折扣配置

    • ...

    更多的场景的接入,让可视化配置的需求变得比较必要。于是开始正式着手构建RuleLink,解决这一类的问题。

    整体结构

    目前主要使用Aviatorscript 解析表达式,并支持SpE

     

    这是从其他复制的一张图(忘记出处),因为和自己的场景几乎一模一样,就直接引用了。

     

    存储模型

     

    Rule_Scene 规则场景

    定义场景,目前场景是固定,现在只支持支付,未来有新场景再加入

    RuleFactObj 事实对象

    RuleFactObjfield 事实对象字段

    定义场景下的事实字段,主要用于将来前端可可视化操作。

    RuleBase 规则库

    定义规则,目前只支持表达式(未来考虑支持 特定脚本,比如groovy),目前只是定义规则命中返回 简单或者复杂数据类型,未来可以考虑执行某个运行(action)。

     

     

    日期格式处理

    日期格式原来的实现是SpEL的方式,这会引发一些问题,所以修改了其源码并重新编译生成支持Aviatorscript 支持的自定义函数方式

    复制代码
     1 /**
     2  * @Author: jijunjian
     3  * @CreateTime: 2023-08-25  17:52
     4  * @Description: 自定义函数初始化
     5  */
     6 @Component
     7 @Slf4j
     8 public class CustomFunctionInitializer implements ApplicationContextAware {
     9 
    10     @Override
    11     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    12         log.info("初始化自定义函数");
    13         AviatorEvaluator.addFunction(new StringToTimestamp());
    14         log.info("初始化自定义函数完成");
    15     }
    16 
    17     /**
    18      * 自定义函数
    19      * 时间字符串转时间戳
    20      */
    21     class StringToTimestamp extends AbstractFunction {
    22         @Override
    23         public AviatorObject call(Map env,
    24                                   AviatorObject arg1, AviatorObject arg2) {
    25             String timeString = FunctionUtils.getStringValue(arg1, env);
    26             String format = FunctionUtils.getStringValue(arg2, env);
    27             // 10位时间戳
    28             long timeStamp = DateUtil.parse(timeString, format).getTime()/1000;
    29             return  AviatorLong.valueOf(timeStamp);
    30         }
    31 
    32         @Override
    33         public String getName() {
    34             return "string_to_timestamp";
    35         }
    36     }
    37 }
    复制代码

     

     

    表达式解析

    使用Aviatorscript解析比较简单,直接上代码

    复制代码
     1   /**
     2      * 根据表达式执行
     3      * @author: jijunjian
     4      * @param factObj
     5      * @param expression
     6      * @return
     7      */
     8     @Override
     9     public boolean fire(Object factObj, String expression){
    10         Map fact = new HashMap<>();
    11         fact.put("data",factObj);
    12         // 对于有字符串的表达式,需要先编译(并缓存,减少生成的临时类)
    13         Expression compiledExpression = AviatorEvaluator.compile(expression,true);
    14         log.info("开始执行表达式:{}, fact:{}", expression, JSONUtil.toJsonStr(factObj));
    15         Boolean flag = (Boolean) compiledExpression.execute(fact);
    16         log.info("开始执行表达式:{}, fact:{}, result:{}", expression, JSONUtil.toJsonStr(factObj), flag);
    17 
    18         return flag;
    19     }
    20 点击并拖拽以移动
    复制代码

     

    交互界面

     

     

    写在最后

    虽然现在的版本距离真正让运营同学能直接用起来了,可能还有一定的距离。比如各种枚举支持选项,门店等动态数据支持选项,返回结果支持动态渲染和选择等都还不不具备。但是1.0版本比原来硬编码,甚至nacos配置已经强上许多了。毕竟还是和两个小伙伴挤压业余时间开发,实为不易,于是来一次简单的聚餐,于是我们预定了未来每次大的版本升级,都来一次

     

     

     

    上一份工作时,就有要构建一个简单易用的规则引擎,一直没能实现,有些许遗憾,今天算是给补上了。

    微信:jijunjian

    成为一名优秀的程序员!

  • 相关阅读:
    k8s晋级之管理容器的计算资源
    剖析容器运行时
    RabbitMQ工作队列
    Google Play如何做ASO优化?影响搜索排名的主要因素.
    最好的电脑数据恢复软件是什么
    FutureTask配合Thread实现处理有返回结果的源码、逻辑与架构分析
    U-Net在2022年相关研究的论文推荐
    真是性价比之王,腾讯云这款88元云服务器已经圈粉无数!
    NCC Mocha v0.1.0 发布,.NET 开发的基于 OpenTelemetry 的 APM 系统
    数据仓库维度建模
  • 原文地址:https://www.cnblogs.com/jijunjian/p/17669719.html