当前位置: 首页 > news >正文

规则引擎架构-基于easy-rules

目录

    • 概念理解
    • 实例和编码
      • 抽象出2条规则
      • 简单的规则引擎
      • 事实1的处理
      • 事实2的处理
    • easy-rules 规则的抽象和执行
      • 事实描述
      • 规则的抽象
        • 默认的规则
      • 动态代理执行规则和动作
        • 规则的执行:org.jeasy.rules.core.DefaultRulesEngine#doFire
        • public class RuleProxy implements InvocationHandler
        • 规则执行监听器
      • 回顾规则执行和监听器的执行过程
      • 扩展

概念理解

描述一个简单的处理:基于一堆现实情况,运用规则引擎、经过处理得到对应的结果,然后再据此做后续的事情

  • fact: 事实,已有的现实情况,即输入信息
  • rules: 规则集合,由一系列规则组成,可能有不同的规则排列
  • rule: 规则,包含基本的判断条件和条件符合要做的动作。
  • condition: 规则的判定条件(特定的判断逻辑 if else)
  • action: 规则判定符合后执行的动作
    在这里插入图片描述

实例和编码

一句话描述: 提着去酒店买酒,需要判断是否成年人,成年人才能购买酒,商店据此卖你酒,你买到了酒就装包里走人,回家喝酒去

接下来看easy-rules的定义和处理。

抽象出2条规则

@Rule(name = "age-rule", description = "age-rule", priority = 1)
public class AgeRule {@Conditionpublic boolean isAdult(@Fact("person") Person person) {return person.getAge() > 18;}@Actionpublic void setAdult(@Fact("person") Person person) {person.setAdult(true);}
}
package org.jeasy.rules.tutorials.shop;import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Fact;
import org.jeasy.rules.annotation.Rule;/*** @author dingqi on 2023/5/26* @since 1.0.0*/
@Rule(name = "alcohol-rule", description = "alcohol-rule", priority = 2)
public class AlcoholRule {@Conditionpublic boolean shopRule(@Fact("person") Person person) {return person.isAdult() == true;}@Actionpublic void shopReply(@Fact("bag") Bag bag) {bag.setSuccess(true);bag.add("Vodka");}
}

简单的规则引擎

// create a rule set
Rules rules = new Rules();
rules.register(new AgeRule());
rules.register(new AlcoholRule());//create a default rules engine and fire rules on known facts
DefaultRulesEngine rulesEngine = new DefaultRulesEngine();

事实1的处理

Facts facts = new Facts();
Person tom = new Person("Tom", 19);
facts.put("person", tom);
Bag bag = new Bag();
facts.put("bag", bag);System.out.println("Tom: Hi! can I have some Vodka please?");
rulesEngine.fire(rules, facts);
System.out.println("Tom: bag is " + bag);

输出:Tom成年了,买到了伏特加

Tom: Hi! can I have some Vodka please?
Tom: bag is Bag{success=true, goods=[Vodka]}

事实2的处理

Person jack = new Person("Jack", 10);
facts.put("person", jack);
Bag bag2 = new Bag();
facts.put("bag", bag2);System.out.println("Jack: Hi! can I have some Vodka please?");
rulesEngine.fire(rules, facts);
System.out.println("Jack: bag is " + bag2);

输出:Jack未成年,无功而返

Jack: Hi! can I have some Vodka please?
Jack: bag is Bag{success=false, goods=[]}

easy-rules 规则的抽象和执行

事实描述

public class Facts implements Iterable<Fact<?>> {private final Set<Fact<?>> facts = new HashSet<>();
/*** A class representing a named fact. Facts have unique names within a {@link Facts}* instance.* * @param <T> type of the fact* @author Mahmoud Ben Hassine*/
public class Fact<T> {private final String name;private final T value;

事实简单就是key、value对, 某个事实的名称,和事实的属性特征(以一切皆对象来看,就是一个一个的对象组成了事实)。(只要在规则条件真正执行前,能明确这些事实就行)

规则的抽象

  • 名称
  • 描述
  • 优先级
  • 执行Facts的的方法

org.jeasy.rules.api.Rule接口 和基础实现类org.jeasy.rules.core.BasicRule

条件和动作注解:

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Condition {}
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Condition {}

默认的规则

class DefaultRule extends BasicRule {private final Condition condition;private final List<Action> actions;DefaultRule(String name, String description, int priority, Condition condition, List<Action> actions) {super(name, description, priority);this.condition = condition;this.actions = actions;}@Overridepublic boolean evaluate(Facts facts) {return condition.evaluate(facts);}@Overridepublic void execute(Facts facts) throws Exception {for (Action action : actions) {action.execute(facts);}}}

动态代理执行规则和动作

使用org.jeasy.rules.api.Rules添加规则时如下:

  • org.jeasy.rules.api.Rules#register
 public void register(Object... rules) {Objects.requireNonNull(rules);for (Object rule : rules) {Objects.requireNonNull(rule);this.rules.add(RuleProxy.asRule(rule));}}

使用org.jeasy.rules.annotation.Rule注解构造的规则是使用RuleProxy构造的
在这里插入图片描述

规则的执行:org.jeasy.rules.core.DefaultRulesEngine#doFire

void doFire(Rules rules, Facts facts) {if (rules.isEmpty()) {LOGGER.warn("No rules registered! Nothing to apply");return;}logEngineParameters();log(rules);log(facts);LOGGER.debug("Rules evaluation started");for (Rule rule : rules) {final String name = rule.getName();final int priority = rule.getPriority();if (priority > parameters.getPriorityThreshold()) {LOGGER.debug("Rule priority threshold ({}) exceeded at rule '{}' with priority={}, next rules will be skipped",parameters.getPriorityThreshold(), name, priority);break;}if (!shouldBeEvaluated(rule, facts)) {LOGGER.debug("Rule '{}' has been skipped before being evaluated", name);continue;}boolean evaluationResult = false;try {evaluationResult = rule.evaluate(facts);} catch (RuntimeException exception) {LOGGER.error("Rule '" + name + "' evaluated with error", exception);triggerListenersOnEvaluationError(rule, facts, exception);// give the option to either skip next rules on evaluation error or continue by considering the evaluation error as falseif (parameters.isSkipOnFirstNonTriggeredRule()) {LOGGER.debug("Next rules will be skipped since parameter skipOnFirstNonTriggeredRule is set");break;}}if (evaluationResult) {LOGGER.debug("Rule '{}' triggered", name);triggerListenersAfterEvaluate(rule, facts, true);try {triggerListenersBeforeExecute(rule, facts);rule.execute(facts);LOGGER.debug("Rule '{}' performed successfully", name);triggerListenersOnSuccess(rule, facts);if (parameters.isSkipOnFirstAppliedRule()) {LOGGER.debug("Next rules will be skipped since parameter skipOnFirstAppliedRule is set");break;}} catch (Exception exception) {LOGGER.error("Rule '" + name + "' performed with error", exception);triggerListenersOnFailure(rule, exception, facts);if (parameters.isSkipOnFirstFailedRule()) {LOGGER.debug("Next rules will be skipped since parameter skipOnFirstFailedRule is set");break;}}} else {LOGGER.debug("Rule '{}' has been evaluated to false, it has not been executed", name);triggerListenersAfterEvaluate(rule, facts, false);if (parameters.isSkipOnFirstNonTriggeredRule()) {LOGGER.debug("Next rules will be skipped since parameter skipOnFirstNonTriggeredRule is set");break;}}}
}

默认的规则引擎直接遍历规则去执行,如果condition执行命中后,则去执行action

public class RuleProxy implements InvocationHandler

在这里插入图片描述

private Object evaluateMethod(final Object[] args) throws IllegalAccessException, InvocationTargetException {Facts facts = (Facts) args[0];Method conditionMethod = getConditionMethod();try {List<Object> actualParameters = getActualParameters(conditionMethod, facts);return conditionMethod.invoke(target, actualParameters.toArray()); // validated upfront} catch (NoSuchFactException e) {LOGGER.warn("Rule '{}' has been evaluated to false due to a declared but missing fact '{}' in {}",getTargetClass().getName(), e.getMissingFact(), facts);return false;} catch (IllegalArgumentException e) {LOGGER.warn("Types of injected facts in method '{}' in rule '{}' do not match parameters types",conditionMethod.getName(), getTargetClass().getName(), e);return false;}
}

规则执行监听器

在规则执行的过程中,可以做各种操作。可以看成规则的扩展点

/*** A listener for rule execution events.** @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com)*/
public interface RuleListener {/*** Triggered before the evaluation of a rule.** @param rule being evaluated* @param facts known before evaluating the rule* @return true if the rule should be evaluated, false otherwise*/default boolean beforeEvaluate(Rule rule, Facts facts) {return true;}/*** Triggered after the evaluation of a rule.** @param rule that has been evaluated* @param facts known after evaluating the rule* @param evaluationResult true if the rule evaluated to true, false otherwise*/default void afterEvaluate(Rule rule, Facts facts, boolean evaluationResult) { }/*** Triggered on condition evaluation error due to any runtime exception.** @param rule that has been evaluated* @param facts known while evaluating the rule* @param exception that happened while attempting to evaluate the condition.*/default void onEvaluationError(Rule rule, Facts facts, Exception exception) { }/*** Triggered before the execution of a rule.** @param rule the current rule* @param facts known facts before executing the rule*/default void beforeExecute(Rule rule, Facts facts) { }/*** Triggered after a rule has been executed successfully.** @param rule the current rule* @param facts known facts after executing the rule*/default void onSuccess(Rule rule, Facts facts) { }/*** Triggered after a rule has failed.** @param rule the current rule* @param facts known facts after executing the rule* @param exception the exception thrown when attempting to execute the rule*/default void onFailure(Rule rule, Facts facts, Exception exception) { }}

回顾规则执行和监听器的执行过程

// 1. 条件执行前
triggerListenersBeforeEvaluate(rule, facts);
try {evaluationResult = rule.evaluate(facts);
} catch(Exception e){// 2. 条件执行失败triggerListenersOnEvaluationError(rule, facts, exception);
}if (evaluationResult) {// 3. 条件执行后(条件满足)triggerListenersAfterEvaluate(rule, facts, true);try {// 4. 动作执行前triggerListenersBeforeExecute(rule, facts);rule.execute(facts);// 5. 动作执行后triggerListenersOnSuccess(rule, facts);} catch (Exception exception) {// 6. 条件执行失败triggerListenersOnFailure(rule, exception, facts);}
}else{// 3. 条件执行后(条件不满足)triggerListenersAfterEvaluate(rule, facts, false);
}

扩展

  1. Java Expression Language (JEXL) :表达式语言引擎

https://commons.apache.org/proper/commons-jexl/apidocs/org/apache/commons/jexl3/JexlEngine.html

  1. MVEL:一个功能强大的基于Java应用程序的表达式语言。

  2. SpEL:Spring表达式语言

name: adult rule
description: when age is greater than 18, then mark as adult
priority: 1
condition: "#{ ['person'].age > 18 }"
actions:- "#{ ['person'].setAdult(true) }"

相关文章:

规则引擎架构-基于easy-rules

目录 概念理解实例和编码抽象出2条规则简单的规则引擎事实1的处理事实2的处理 easy-rules 规则的抽象和执行事实描述规则的抽象默认的规则 动态代理执行规则和动作规则的执行&#xff1a;org.jeasy.rules.core.DefaultRulesEngine#doFirepublic class RuleProxy implements Inv…...

【数据结构】第七周

目录 稀疏矩阵快速转置 三元组的矩阵加法 九宫格数独游戏 数组主元素 螺旋数字矩阵 蛇形矩阵 数组循环右移K位 稀疏矩阵快速转置 【问题描述】 稀疏矩阵的存储不宜用二维数组存储每个元素&#xff0c;那样的话会浪费很多的存储空间。所以可以使用一个一维数组存…...

人体三维重构论文集合:awesome 3d human reconstruction

A curated list of related resources for 3d human reconstruction. Your contributions are welcome! Contents papers AIGCnerf or pifugeo fusionphoto3D human whole body3D human...

揭秘Redis持久化原理,探索fork与Copy-on-Write的魔法!

大家好&#xff0c;我是小米&#xff0c;今天我将和大家一起探索Redis持久化原理中的两个关键概念&#xff1a;fork和Copy-on-Write。这两个概念对于理解Redis的数据持久化机制至关重要。让我们一起来揭开这些技术的神秘面纱吧&#xff01; Redis持久化简介 在开始之前&#…...

应届生如何提高职场竞争能力

摘要&#xff1a; 应届生面对竞争激烈的职场&#xff0c;需要不断提高自身的职业素养和竞争能力&#xff0c;才能在激烈的竞争中脱颖而出。本文从积极心态的培养、专业知识的优化、职业规划的制定、团队协作的加强和自我拓展的开展五个方面&#xff0c;提出了提高应届生职场竞争…...

ISIS 实验

(1)拓扑图 2&#xff09;需求&#xff1a; -实现PC1和PC2的通信 3&#xff09;配置步骤&#xff1a; -配置接口IP地址 -开启ISIS---类似于在OSPF中创建进程 -配置NET地址---类似于在OSPF中创建区域&#xff0c;指定Router-id -在接口上启用ISIS--类似于在OSPFv2中用ne…...

国产系统:麒麟之人大金仓数据库部署

一、基本信息和资源 1.1 查看服务器信息 [root7PGxjKPL4 ~]# cat /etc/*release Kylin Linux Advanced Server release V10 (Sword) DISTRIB_IDKylin DISTRIB_RELEASEV10 DISTRIB_CODENAMEjuniper DISTRIB_DESCRIPTION"Kylin V10" DISTRIB_KYLIN_RELEASEV10 DISTRI…...

flink1.17.0 集成kafka,并且计算

前言 flink是实时计算的重要集成组件&#xff0c;这里演示如何集成&#xff0c;并且使用一个小例子。例子是kafka输入消息&#xff0c;用逗号隔开&#xff0c;统计每个相同单词出现的次数&#xff0c;这么一个功能。 一、kafka环境准备 1.1 启动kafka 这里我使用的kafka版本…...

【华为OD机试】数组组成的最小数字【2023 B卷|100分】

【华为OD机试】-真题 !!点这里!! 【华为OD机试】真题考点分类 !!点这里 !! 题目描述: 给定一个整型数组,请从该数组中选择3个元素组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述: 一行用半角逗号分割的字符串记录的整型数…...

Exponential Loss 中的关于indicator 函数的一个恒等式

− x y 2 I ( x ≠ y ) − 1 -xy2\mathbf{ I}(x \ne y)-1 −xy2I(xy)−1 其中 I \mathbf{ I} I 是 indicator 函数&#xff0c; 定义域 为True &#xff0c;函数值为 1 反之为 0 x,y 都 可以取值 {-1,1} 证明过程见下表&#xff1a; xy左式右式-1-1-1-111-1-1-11111-111...

【机器学习】浅析过拟合

过度拟合 我们来想象如下一个场景&#xff1a;我们准备了10000张西瓜的照片让算法训练识别西瓜图像&#xff0c;但是这 10000张西瓜的图片都是有瓜梗的&#xff0c;算法在拟合西瓜的特征的时候&#xff0c;将西瓜带瓜梗当作了一个一般性的特征。此时出现一张没有瓜梗的西瓜照片…...

尝试在UNet的不同位置添加SE模块

目录 &#xff08;1&#xff09;se-unet01&#xff08;在卷积后&#xff0c;下采样前&#xff0c;添加SE模块&#xff09; &#xff08;2&#xff09;se-unet02&#xff08;在卷积后&#xff0c;上采样前&#xff0c;添加SE模块&#xff09; &#xff08;3&#xff09;se-un…...

JVM垃圾回收篇之相关概念和算法

垃圾回收相关概念 什么是垃圾 垃圾就是指在运行程序中没有任何指针指向的对象,这个对象就是需要被回收掉的垃圾,如果不及时进行清理,越积越多就会导致内存溢出. 为什么需要GC 不进行回收,早晚会导致内存溢出,Java自动管理垃圾回收,不需要开发人员手动干预,这就有可能导致开…...

(学习日记)2023.04.27

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…...

亚马逊CPC广告每日该怎么调整?

01 CPC广告需要每日调整吗&#xff1f; 其实&#xff0c;亚马逊广告是不建议每天都做过多调整的。 为什么呢&#xff1f;调整太频繁了&#xff0c;看不到每天调整的结果是不是&#xff1f; 什么时候需要调整呢&#xff1f; 就是广告指标&#xff0c;比如说曝光、点击、转化率情…...

ffmpeg下载及ffmpy3安装使用

ffmpeg下载及ffmpy3安装使用 1.下载ffmpeg 进入网址&#xff1a;https://www.gyan.dev/ffmpeg/builds/ 在release builds中下载ffmpeg-release-full.7z 下载好后解压到自己想存放的目录&#xff0c;例如&#xff1a;D:\Tool\ffmpeg-6.0-full_build 2.配置环境变量 右键此电…...

设计模式之~原型模式

定义&#xff1a;用原型实例指导创建对象的种类&#xff0c;并且通过拷贝这些原型创建新的对象。原型模式其实就是从一个对象再创建另外一个可定制的对象&#xff0c;而且不需知道任何创建的细节。 优点&#xff1a; 一般在初始化的信息不发生变化的情况下&#xff0c;克隆是最…...

多传感器融合SLAM --- 8.LIO-SAM基础知识解读

目录 1 惯性测量单元简介及预积分 1.1 IMU 器件介绍及选型建议 1.2 IMU状态传递方程...

多模态大模型时代下的文档图像智能分析与处理

多模态大模型时代下的文档图像智能分析与处理 0. 前言1. 人工智能发展历程1.1 传统机器学习1.2 深度学习1.3 多模态大模型时代 2. CCIG 文档图像智能分析与处理论坛2.1 文档图像智能分析与处理的重要性和挑战2.2 文档图像智能分析与处理高峰论坛2.3 走进合合信息 3. 文档图像智…...

SAP-MM-内向外向交货单

1、内向&外向交货单概念 外向交货&#xff08;outbound delivery&#xff09;是用在客户与企业之间的交货单&#xff0c;而内向交货&#xff08;inbound delivery&#xff09;则是用在供应商与企业之间的交货单&#xff1b;换言之&#xff0c;外向交货多用于SD 模块&#…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)

引言 工欲善其事&#xff0c;必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后&#xff0c;我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集&#xff0c;就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...

通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器

拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件&#xff1a; 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...

HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散

前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说&#xff0c;在叠衣服的过程中&#xff0c;我会带着团队对比各种模型、方法、策略&#xff0c;毕竟针对各个场景始终寻找更优的解决方案&#xff0c;是我个人和我司「七月在线」的职责之一 且个人认为&#xff0c…...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态

前言 在人工智能技术飞速发展的今天&#xff0c;深度学习与大模型技术已成为推动行业变革的核心驱动力&#xff0c;而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心&#xff0c;系统性地呈现了两部深度技术著作的精华&#xff1a;…...