分享好友 最新动态首页 最新动态分类 切换频道
Easy Rules规则引擎实战
2024-12-26 23:57

Easy Rules规则引擎实战

1、是什么

  • 基于java轻量级的规则引擎,学习成本更低、适用性更强
  • 本质一个函数,y=f(x1,x2,…,xn)
  • Easy Rules 每条规则都有一个条件(condition)和一个动作(action,简单地说,可以将其看作是一组 IF THEN 或类似SQL的when-then语句

2、作用

  • 解决业务代码和业务规则分离,实现了将业务决策从应用程序代码中分离。 接受数据输入,解释业务规则,并根据业务规则做出业务决策。

业务系统在应用过程中,常常包含着要处理"复杂、多变"的部分,这部分往往是"业务规则"或者是"数据的处理逻辑"。因此这部分的动态规则的问题,往往需要可配置,并对系统性能和热部署有一定的要求。从开发与业务的视角主要突出以下的一些问题

  • 从开发人员视角来看

1)逻辑复杂,要使用大量if-else来实现,或者使用设计模式。但过于复杂的规则逻辑,使用设计模式也往往是存在大量并且关系复杂的类,导致代码难于维护,对新加入的同学极不友好。

2)变更时需要从头梳理逻辑,在适当的地方进行if…else…代码逻辑调整,耗费大量时间进行梳理。

3)开发周期较长,当需求发生变更时,需要研发人员安排开发周期上线,对于当下快速变化的业务,传统的开发工作方式显得捉襟见肘。

  • 从业务人员视角来看

1)业务人员期望友好的管理界面,不需要专业的开发技能就能够完成规则的管理、发布。

2)期望能够实现热部署,由业务人员配置好之后即配即用。

3)减少业务规则对开发人员的依赖。

4)降低需求变动的时间成本,快速验证发布

3、怎么做

你可以自己构建一个简单的规则引擎。你所需要做的就是创建一组带有条件和动作的规则对象rule,将它们存储在一个集合中rules,然后遍历它们以评估(fire)条件(condition)并执行这些动作(action)。

pom

 
 

大多数业务规则可以由以下定义表示

  • 名称name:规则命名空间中的唯一规则名称

  • 说明description:规则的简要说明

  • 优先级priority:相对于其他规则的规则优先级,较小的值表示较高的优先级

  • 事实fact:去匹配规则时的一组已知事实

  • 条件condition:为了匹配该规则,在给定某些事实的情况下应满足的一组条件

    如果规则条件为true,则规则将被触发执行。否则,规则将被忽略

  • 动作action:当条件满足时要执行的一组动作(可以添加/删除/修改事实

    它可以用于实现各种应用程序逻辑,例如更新数据、发送消息等。

抽象规则Rule

 

基础规则BasicRule

 
事实类Facts:map
 
  • 扩展:可以将普通对象(包含属性|方法)facts.put()。也可以将rpc对象put进来
 
条件接口
 
动作接口
 

四种规则定义方式

注解方式

1、eg1(也可以实现Rule接口

 

2、纯注解

 
RuleBuilder 链式

1、eg1

 

2、eg2

 
Mvel和Spel表达式

1、eg1:Mvel表达式

Mvel表达式

 
  • when:对象属性

when方法参数,只能是facts对象中key对象,内部定义的属性或方法

 

2、补充

  • when、then内容,可以从自定义的json文件中读取并解析成Mvel表达式形式。解析过程可参考场景6

3、eg2:Spel表达式同理

Spel表达式

Yml配置

eg1: weather-rule.yml

 
  • condition:对象方法
 

eg2:一个yml文件创建多个规则

 
  • 读取多条规则
 

常用规则类

DefaultRule
 
SpELRule(Spring的表达式注入

表达式注入

 
  • when方法-SpELCondition
 
  • then方法- SpELAction
 

组合规则

抽象CompositeRule类由一组规则组成。这是一个典型地组合设计模式的实现。可以以不同方式触发组合规则。

三种CompositeRule具体子类

UnitRuleGroup : 要么应用所有规则,要么不应用任何规则(AND逻辑
ActivationRuleGroup : 它触发第一个适用规则,并忽略组中的其他规则(XOR逻辑
ConditionalRuleGroup : 如果具有最高优先级的规则计算结果为true,则触发其余规则

UnitRuleGroup
  • 规则1
 
  • 规则2
 
  • 执行
 
  • 输出
 

先输出规则2(优先级为777,规则1(优先级为默认值:2147483646,值越小,优先级越高

引擎接口

 

引擎抽象类

AbstractRuleEngine作用就是抽出多个引擎类共有的,不需要再各自额外重复去实现

引擎类-DefaultRulesEngine

 
规则引擎参数(决定规则之间是否互斥|中断|跳过等)

RulesEngineParameters

 
 

场景1- 恒打印

规则description

默认打印Hello World

规则
 
规则引擎:使用DefaultRulesEngine
执行
 

输出

 
fire方法执行流程
 

场景2-yml

1、规则description

if it rains then take an umbrella

2、定义规则

weather-rule.yml

 

3、自定义规则引擎:使用默认的

4、执行

 

场景3 简单if-else

1、功能描述

从1数到100,并且:

  • 需求1:如果数字是5的倍数,则打印"i :是5的倍数"
  • 需求2:如果数字是7的倍数,请打印"i :是7的倍数"
  • 需求3:如果数字是5和7的倍数,请打印"i :是5的倍数、7的倍数"
  • 需求4:否则打印数字本身

2、常规实现方法

 

3、使用Easy Rules规则引擎实现

将每个需求编写一条规则:

  • rule1
 
  • rule2
 
  • rule3
 
  • rule4
 
  • 执行
 
  • 这里规则引擎参数:skipOnFirstAppliedRule(true):告诉引擎,被触发时跳过后面的规则。

    即当i = 5时,满足规则1(mod5,执行完action1,就不会再去匹配其他rule2、3、4规则了。使用场景是:各个规则之间互斥

场景4-动态规则MVEL表达式+Json字符串

如图1

输入facts:NORMAL_NUMBER和ERROR_NUMBER两个值,使用Mvel表达式解析facts是否满足上述json中定义的condition

  • 操作符枚举类(加减乘除,> 、<)
 
  • 逻辑运算符(&&、||、and、or
 
  • 工具类(负责解析自定义json字符串中的condition和action内容,赋值给Mvel规则when、then
 
  • 测试
 

结果分析:显然结果匹配成功。原因如图2

facts:NORMAL_NUMBER = 10、ERROR_NUMBER = 10

condition:如图1

显然NORMAL_NUMBER = 10,满足第一个条件 < 11,直接返回true。

如果我们设置fact:NORMAL_NUMBER = 12,则NORMAL_NUMBER 不满足第一个条件。

但是fact中ERROR_NUMBER = 10 <= 11满足第二个条件,直接返回True

场景5-QLExpress

1、使用阿里的QLExpress

 
 
  • MetaRuleResult
 

2、使用EasyRules实现上述功能

  • 规则1
 

这里的规则是原子规则

  • 规则2
 
  • 自定义组合规则
 

作用:这里的规则是组合规则,是原子规则的组合形式,可扩展

这里的自定义规则组合,是快速失败机制:即l&&o中如果lRule的condiotion为false,则直接失败,使用facts记录一个失败原因。也可以自定义将每个rule-condition为false的原因都记录下来

  • 自定义condition-after-listeren
 

作用:组合规则,执行结果。成功|失败,已经失败原因

  • 执行
 
  • 扩展

1)db获取规则表达式

先根据网店+品类+角色+修改类型,查询db获取组合规则,比如l&&o

2)工厂模式解析组合规则

然后根据l&&o,解析出规则为l和o,组合成l&&o

3)facts获取数据

自定义策略模式,key为枚举类型,value为对应的rpc查询接口

 

这里的queryData方法,根据规则类型o,获取对应的Rpc接口-ORGateway,然后查询or值,然后比较结果

4)组合规则中,判断每个原子规则是否执行通过,失败则记录对应执行失败原因

5)在condition-after中自定义listeren,如果组合规则condition为false,则记录组合规则整体的执行失败以及失败原因

6)如果组合规则整体执行失败,则本次结果为false

场景6- 动态规则Mvel + Json文件

1、背景

动态规则就是由于业务场景的变化,之前的规则已经不适用现在的业务场景,需要更改相对应的规则。

例如:之前是满300减30,现在是满200-30

  • 正常情况下我们需要改规则类里面的比较参数代码,然后打包上线。
  • 如果使用动态规则,修改一下配置中的规则json文件即可,线上代码会读取最新的规则配置文件,无需上线

2、前提说明

1)规则类中的condtion方法,可以入参传入Facts参数,然后使用facts.get()方法获取内容 ,但是规则文件(eg:json)的condtion中无法传入Facts参数,也就无法使用此参数

2) 自定义RuleListener监听会作用到所有执行的规则,如何仅处理我们指定的规则

 

3、场景

  • 输入一个人的信息,信息中包含了这个人的学历等级,作为规则事实

    • 方式一:condition中制定(推荐,可以动态配置0和11
    • @Condition修饰方法入参( @Fact(“person”) Person person )
     
      
    • 方式二:将condition条件判断,自定在fact-key中对象的属性和方法中(不推荐
 
 
  • 如果学历等级符合规则,则去查询学历证书情况(集合存储)

  • 查出完学历证书后,在检测学历证书与他的学历等级是否匹配,匹配规则为

    • 学历证书数量与学历等级相同
    • 最大学历证书的学历等级与学历等级一致
  • 匹配通过则学历真实,信息中会添加真实学历匹配结果

  • 未匹配通过则学历造假嫌疑,信息中会添加造假学历信息

上线

2、前提说明

1)规则类中的condtion方法,可以入参传入Facts参数,然后使用facts.get()方法获取内容 ,但是规则文件(eg:json)的condtion中无法传入Facts参数,也就无法使用此参数

2) 自定义RuleListener监听会作用到所有执行的规则,如何仅处理我们指定的规则

 

3、场景

  • 输入一个人的信息,信息中包含了这个人的学历等级,作为规则事实

    • 方式一:condition中制定(推荐,可以动态配置0和11
    • @Condition修饰方法入参( @Fact(“person”) Person person )
     
      
    • 方式二:将condition条件判断,自定在fact-key中对象的属性和方法中(不推荐
 
 
  • 如果学历等级符合规则,则去查询学历证书情况(集合存储)

  • 查出完学历证书后,在检测学历证书与他的学历等级是否匹配,匹配规则为

    • 学历证书数量与学历等级相同
    • 最大学历证书的学历等级与学历等级一致
  • 匹配通过则学历真实,信息中会添加真实学历匹配结果

  • 未匹配通过则学历造假嫌疑,信息中会添加造假学历信息

场景7-履约缺货处罚金额计算

1、背景

如果商家发生了履约缺货,则需要对商家进行罚款,罚款金额计算的逻辑如下

这里以skuId=1,skuName=“苹果”, 供应商id=777为例

  • 假设供应商777,履约缺货了3件,即less = 3 pcs
  • 此sku的销售Gmv即saleGmv = 100元
  • 此sku的销售件数即saleCount = 5 pcs

则需要对777这个商家,关于skuId=1的品进行罚款,罚款金额Java代码实现如下

 
  • 缺点1

这里商家skuId=1缺货了3件,按照这个逻辑Java代码实现没有问题,加入skuid=1缺货了300件,则不能按照这个罚款的计算逻辑,计算逻辑就要重新Java代码实现,或者大量的if-else。这里仅有6中分支,加入分支很多很多,则代码变得异常臃肿。

  • 缺点2

假如代码实现后,那天业务变更了计算公式的一个值,或者干脆改变了计算逻辑max->min,则只能通过代码上线。

  • 使用when-then形式解决大量分支问题,而且支持动态加载,无需上线代码

实现如下

2、实现

 

3.监听器

通过监听器,如果then执行成功了,则一定会执行监听器的onSuccess方法。故在此再执行一遍then表达式,获取then的执行结果存入map中(这里之所以要通过监听器来存then的结果,原因是原生的MvelRule规则的execute方法返回值类型是void,它只关系then中的表达式是否执行成功,不关系表达式执行的结果

 

补充

1.调用类的带参数方法

 

2.调用类不带参方法

 

场景8:Mvel表达式when-then调用类方法

1、背景

当满足when(指定类的方法,则执行then(执行类的方法

2、举例

  • 定义类的when-then方法
 
  • 执行
 

场景9:终极模式之规则引擎+职责链

我mjp愿称之为EasyRules最强实战场景2024.01.07

1、背景

综合上述场景7和8。

我们知道规则的处罚动作actions可能不止一个。除了对商家进行罚款,还可以对商家停排期,甚至可以降低商家商品的曝光度等等一系列处罚动作。

基于此,我们可以将处罚actions配置为json字符串

 

2、特殊化

规则1

  • when是 0<less<=10
  • actions是
 

规则2

  • when是 0<less<=10
  • actions是
 

即规则2的处罚动作只有罚款

那么问题来了,如何为每个规则,定制化处罚actions动作

答案:通过职责链模式

3、思想

  • 我们代码中使用职责链模式,定义一系列的Handler处理器。

然后每一条规则的actions =》映射成List handlerList,然后遍历执行处理器。

  • 因为不同的规则,处罚动作actions可能不一样,所以,其处理器handlerList也不尽相同,需要自己定制化

4、代码实现

  • 业务代码执行
 
  • 方法类Demo
 
  • 处理器接口
 
  • 处理器实现类

    罚款处理器

 

​ 停排处理器

 
  • 根据入参定制化处理器集合

    处理器接口默认都不参与,根据json的key添加谁参与

     
 

5、罚款处理器扩展

罚款处理器中,也可以使用Mvel表达式,直接计算罚款多少钱

 
补充:MVEL直接调用类方法

1.调用类的带参数方法

 

2.调用类不带参方法


最新文章
逾期通讯录消除攻略:如何有效处理不良记录,恢复信用?
1. 到相关的逾期联系人管理平台或应用。2. 找到逾期联系人的列表,常常这些列表会在“逾期管理”或“联系人管理”等板块中。3. 选中您想要撤销的逾期联系人。4. 点击“编辑”或“管理”按,进 系人的详细信息页面。5. 查找“撤销逾期”或“
长沙十大网络舆情公关公司排名揭晓:为城市形象护航
在当今信息高速传播的时代,网络舆情的影响力日益凸显。长沙,这座充满活力的城市,也有着一批专业的网络舆情公关公司,在维护城市形象和企业声誉方面发挥着重要作用。长沙网络舆情公关公司具备先进的舆情监测技术。他们能够实时监控各类网
超好用:免费好用的图床
经常写文章的小伙伴可能会头疼,图片需要一张一张的上传,费劲也耗时,今天就推荐几款超简单的图床工具。图床就是一个在网络上存储图片的地方,目的是为了节省本地服务器空间,加快图片打开速度。话不多说,进入正题。永久存储免注册,图片
探秘系统设计界面神器,打造精美交互界面
在当今数字化浪潮汹涌澎湃的时代,系统设计界面的质量直接关乎用户与软件、平台交互的顺畅性与愉悦感。一款出色的系统设计界面软件,犹如一位幕后的魔法大师,能够将设计师的创意灵感精准地转化为直观、实用且富有魅力的用户界面。无论是打
魔音工坊的文案制作过程融合了先进的人工智能技术和大数据分析,为客户提供了一种全新的文案创作体验。以下是具体步骤和优化后的
在数字化时代人工智能的应用已经渗透到各行各业文案创作也不例外。魔音工坊作为一家专注于音频制作和文案生成的企业凭借其特别的技术,为广大创作者提供了高效、便捷的文案生成解决方案。本文将深入探讨魔音工坊的文案制作过程,揭示其背后
淘宝店铺该应该如何补单才会迅速的提升排名?
五、成交额=客单价成交笔数,成交笔数=流量转化率,流量=直通车投入费用/平均点击费用六、利润=营业额利润率=客户价格成交笔数利润率=客户价格流量转换率利润率=客户价格转换率转换率开通费用/平均点击费用在综合排名中,店铺质量得分会影
重磅通报“正宗南通长牌怎么开挂”玩家曝光开挂详情-知乎
您好:正宗南通长牌这款游戏可以开挂,确实是有挂的,咨询加微信【5722507】很多玩家在这款游戏中打牌都会发现很多用户的牌特别好,总是好牌,而且好像能看到其他人的牌一样。所以很多小伙伴就怀疑这款游戏是不是有挂,实际上这款游戏确实
抖音直播的5种主流玩法
抖音直播的主流玩法有哪些,抖音是时下特别热门的营销平台,那么在直播方面有哪些主流玩法呢。一起来看看下面的介绍吧。1、 模式分析:兴趣电商+Tiktok选择联盟,即商家在选择联盟中选择高佣金产品,使用直播内容(如前文写的跑步)激发观
苹果手机最好用的浏览器【手机最好用的浏览器 知乎】
有时候我们在手机上看视频或听音乐时,遇到好的在线资源想下载回来,这时就需要用到嗅探功能去找到资源的真实地址,再把它下载到手机里。带有这种功能的浏览器在安卓系统的手机里比比皆是,但苹果手机里却是凤毛麟角,不是功能不够好,就是
相关文章
推荐文章
发表评论
0评