easy rule 学习记录

news2024/11/25 11:46:24

总体:

使用方面除了官网的wiki外,推荐阅读

作者:夜尽天明_
链接:https://juejin.cn/post/7048917724126248967
来源:稀土掘金

  • 非annotation 方式,执行不是jdk proxy模式
  • annotation 方式,和rulebook 类似使用jdk
    proxy模式,但由于本质居于pojo和继承模式,proxy调用比较简单,采用return class类指定方法
  • 每个rule 只有一个action方法,这点与rulebook不同
  • 支持CompositeRule,默认有3种,但不支持rulebook chain式按order执行
  • 两种执行引擎,DefaultRulesEngine 只执行一次,InferenceRulesEngine 会循环执行,直到所有rule的evaluation 返回false
  • evaluation 相当于rulebook的condition,action相当于rulebook 的then

核心类及代码

public final class DefaultRulesEngine extends AbstractRulesEngine 的执行函数

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;
        }
        //执行listener ,如果有返回false ,那么就不执行当前rule
        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 false
            if (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;
            }
        }
    }
}

private boolean shouldBeEvaluated(Rule rule, Facts facts) {
    return triggerListenersBeforeEvaluate(rule, facts);
}
private boolean triggerListenersBeforeEvaluate(Rule rule, Facts facts) {
    return ruleListeners.stream().allMatch(ruleListener -> ruleListener.beforeEvaluate(rule, facts));
}

public final class InferenceRulesEngine extends AbstractRulesEngine 循环执行,指定facts结果满足了所有condition都不符合,才停止执行相关rules的核心代码如下:

@Override
public void fire(Rules rules, Facts facts) {
    Set<Rule> selectedRules;
    //默认只要有selectCandidates(rules, facts) 就会执行,如果facts 没有变化那么selectCandidates返回rules就会一直一样,即不断循环执行
    do {
        LOGGER.debug("Selecting candidate rules based on the following facts: {}", facts);
        selectedRules = selectCandidates(rules, facts);
        if (!selectedRules.isEmpty()) {
            delegate.fire(new Rules(selectedRules), facts);
        } else {
            LOGGER.debug("No candidate rules found for facts: {}", facts);
        }
    } while (!selectedRules.isEmpty());
}

private Set<Rule> selectCandidates(Rules rules, Facts facts) {
    Set<Rule> candidates = new TreeSet<>();
    //如果facts 没有变化
    for (Rule rule : rules) {
        if (rule.evaluate(facts)) {
            candidates.add(rule);
        }
    }
    return candidates;
}

使用InferenceRulesEngine 一定要修改fact。

UnitRuleGroup 所有rule作为一个整体判断是否执行

@Override
public boolean evaluate(Facts facts) {
    if (!rules.isEmpty()) {
        for (Rule rule : rules) {
            if (!rule.evaluate(facts)) {
                return false;
            }
        }
        return true;
    }
    return false;
}

public class ActivationRuleGroup extends CompositeRule
通过selectedRule来(随机)选择了第一个condition符合的rule

@Override
public boolean evaluate(Facts facts) {
    for (Rule rule : rules) {
        if (rule.evaluate(facts)) {
            selectedRule = rule;
            return true;
        }
    }
    return false;
}

public class ConditionalRuleGroup extends CompositeRule 首先判断RuleWithHighestPriority的condition是否满足,如果满足再选择重所有condition符合的rule进行fire

@Override
public boolean evaluate(Facts facts) {
    successfulEvaluations = new HashSet<>();
    conditionalRule = getRuleWithHighestPriority();
    if (conditionalRule.evaluate(facts)) {
        for (Rule rule : rules) {
            if (rule != conditionalRule && rule.evaluate(facts)) {
                successfulEvaluations.add(rule);
            }
        }
        return true;
    }
    return false;
}


private Rule getRuleWithHighestPriority() {
    List<Rule> copy = sort(rules);
    // make sure we only have one rule with the highest priority
    Rule highest = copy.get(0);
    if (copy.size() > 1 && copy.get(1).getPriority() == highest.getPriority()) {
       throw new IllegalArgumentException("Only one rule can have highest priority");
    }
    return highest;
}

RuleGroup支持从yml自动创建,或者手工创建,yml自动创建代码

switch (ruleDefinition.getCompositeRuleType()) {
    case "UnitRuleGroup":
        compositeRule = new UnitRuleGroup(name);
        break;
    case "ActivationRuleGroup":
        compositeRule = new ActivationRuleGroup(name);
        break;
    case "ConditionalRuleGroup":
        compositeRule = new ConditionalRuleGroup(name);
        break;
    default:
        throw new IllegalArgumentException("Invalid composite rule type, must be one of " + ALLOWED_COMPOSITE_RULE_TYPES);
}

代码创建

public void setUp() {
conditionalRule = new TestRule("conditionalRule", "description0", 0, true);
rule1 = new TestRule("rule1", "description1", 1, true);
rule2 = new TestRule("rule2", "description2", 2, true);
conditionalRuleGroup = new ConditionalRuleGroup();
conditionalRuleGroup.addRule(rule1);
conditionalRuleGroup.addRule(rule2);
conditionalRuleGroup.addRule(conditionalRule);
rules.register(conditionalRuleGroup);
}

从yml文件创建都基于AbstractRuleFactory类

在这里插入图片描述

扩展

可以根据需要去扩展AbstractRuleFactory和CompositeRule,依托priority属性实现类似rulebook 的chain 执行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/750665.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux操作系统】线程控制

文章目录 线程创建线程等待终止线程利用多线程求和(单进程多线程)获取线程ID取消线程线程分离共享&#xff1f; 线程创建 创建线程需要用的函数是pthread_create。函数原型如下&#xff1a; int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start…

left join 和except方法区别和联系

目录 相同点&#xff1a; left join except 不同点 假设有两个表&#xff1a;A客户表 和 B客户表&#xff0c;客户uid是唯一主键 相同点&#xff1a; 查询在A中的客户 但不在B中&#xff0c;也就是图中的阴影部分&#xff0c;left join 和except方法都可以实现 left join …

Harnessing the Power of LLMs in Practice: A Survey on ChatGPT and Beyond

LLM的系列文章&#xff0c;针对《Harnessing the Power of LLMs in Practice: A Survey on ChatGPT and Beyond》的翻译。 在实践中驾驭LLM的力量——ChatGPT及其后的研究综述 摘要1 引言2 模型实用指南2.1 BERT风格的语言模型&#xff1a;编码器-解码器或仅编码器2.2 GPT风格…

python接口自动化(三十五)-封装与调用--流程类接口关联(详解)

简介 流程相关的接口&#xff0c;主要用 session 关联&#xff0c;如果写成函数&#xff08;如上篇&#xff09;&#xff0c;s 参数每个函数都要带&#xff0c;每个函数多个参数&#xff0c;这时候封装成类会更方便。在这里我们还是以博客园为例&#xff0c;带着小伙伴们实践一…

spring复习:(24)ApplicationContext中的BeanPostProcess是在哪里注册到容器的?

在ApplicationContext实现类的构造方法里。 public ClassPathXmlApplicationContext(String configLocation) throws BeansException {this(new String[] {configLocation}, true, null);}上边的构造方法调用如下构造方法 public ClassPathXmlApplicationContext(String[] conf…

ubuntu使用WHEELTE N100并用rviz显示

写在最开头&#xff0c;如果wheeltec n100被自己改动过参数导致无法读取数据&#xff0c;建议在window的上位机中恢复出厂设置并重新上电&#xff0c;在转入ubuntu。因为我就是这个问题&#xff0c;客服远程操控才帮我解决的。 所有官方资料共享&#xff0c;侵删&#xff1a; …

Flink+StarRocks 实时数据分析新范式

摘要&#xff1a;本文整理自 StarRocks 社区技术布道师谢寅&#xff0c;在 Flink Forward Asia 2022 实时湖仓的分享。本篇内容主要分为五个部分&#xff1a; 极速数据分析 实时数据更新 StarRocks Connector For Apache Flink 客户实践案例 未来规划 点击查看原文视频 &a…

一篇文章让你看懂C语言字符函数和内存函数

目录 一、字符函数 1.strlen函数 1.1strlen函数的介绍 1.2strle函数的使用 1.3模拟实现strlen 1.3.1指针移动法 1.3.2指针减去指针法 1.3.3函数递归法 2.strcpy函数 ​编辑 2.1strcpy函数的介绍 2.2strcpy函数的使用 2.3模拟实现strcpy 3.strcat函数 3.1strcat函数的介…

LiveGBS流媒体平台GB/T28181功能-支持海康大华GB28181语音对讲需要的设备及服务准备

LiveGBS支持海康大华GB28181语音对讲需要的设备及服务准备 1、背景2、准备2.1、服务端必备条件&#xff08;注意&#xff09;2.2、准备语音对讲设备2.2.1、 大华摄像机2.2.1.1、 配置接入示例2.2.1.2、 配置音频通道编号 2.2.2、 海康摄像机2.2.2.1、 配置接入示例 3、开启音频…

初试Python路径库

文章目录 一、pathlib概述二、操作路径对象(一)操作属性(二)连接路径(三)拆分完整路径三、路径对象的常用函数(一)获取当前工作目录(二)创建新目录(三)查看主目录一、pathlib概述 自Python 3.4 以来,pathlib一直是标准库的一部分。 PurePath, PurePosixPath, Pure…

即视角|出海资本热土——印尼市场洞察(上)

即视角Insight 共享即构新洞察&#xff0c;共建行业新动能——ZEGO即构科技基于音视频技术领域的多年深耕&#xff0c;综合面向各行业的服务经验&#xff0c;在【即视角】栏目发布即构对行业的洞察。 此前我们根据即构对出海客户的服务经验&#xff0c;输出了文章《即视角&am…

STL标准模板库 set容器

文章目录 迭代器迭代器的五大分类迭代器系列帮手函数一览 set容器打印任意 STL 容器的printer.hset与vectorset 和 vector 的区别set 和 vector 迭代器的共同点set 和 vector 迭代器的不同点 set 的排序set 的排序&#xff1a;string 会按“字典序”来排set 的排序&#xff1a;…

ai智能绘画生成器有哪些?你知道ai生成图片网站哪个好吗?

曾经有一个年轻的画家&#xff0c;名叫亚历克斯。他对艺术充满了热情和渴望&#xff0c;但却常常感到自己的创作灵感有限。每当他拿起画笔&#xff0c;总是困扰于如何将心中的景象完美地呈现在画布上。 有一天&#xff0c;亚历克斯偶然听说了一个神奇的网站&#xff0c;据说这…

【力扣】20. 有效的括号

有效的括号 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 每个右括号都有一个对应的相…

uniapp H5预览PDF文件

1&#xff0c;下载资源后hybrid文件存放在static静态文件里 (点击这里去下载文件) 2&#xff0c;pdf预览页面配置 <template><view style"width: 100vh;"><web-view :src"pdfUrl"></web-view></view> </template><…

【每日一题】1289. 下降路径最小和 II

【每日一题】1289. 下降路径最小和 II 1289. 下降路径最小和 II题目描述解题思路 1289. 下降路径最小和 II 题目描述 给你一个 n x n 整数矩阵 grid &#xff0c;请你返回 非零偏移下降路径 数字和的最小值。 非零偏移下降路径 定义为&#xff1a;从 grid 数组中的每一行选择…

【计算机视觉】简述对EQ-Net的理解

最近又看了一些点云分割的文章&#xff0c;近两年点云分割的文章是真的少&#xff0c;不知道是不是点云分割算法接近了末端。这篇文章主要提出了一个基于查询方法的统一范式&#xff0c;它解决了一些不仅仅是点云分割的问题&#xff0c;还解决了三维点云分类和三维目标检测的问…

解密AI图像安全技术:智能守护数智时代,低代码平台助力圈复杂操作!

前言 随着数智时代的来临&#xff0c;人们进入了一个全新的智能化世界。在这个时代中&#xff0c;人工智能&#xff08;AI&#xff09;成为了一项重要的技术突破&#xff0c;其应用也无处不在。其中&#xff0c;AI图像安全技术作为保障个人和企业数据安全的重要环节&#xff0c…

Linux——认识Linux的目录结构 常用命令 vim命令 权限及其控制

目录 linux的目录结构常用linux的命令ls(list)和llcd 切换目录mkdir 创建文件夹touch命令&#xff1a;创建普通文本文件pwd 显示路径whoamisu&#xff1a;普通--超级账号man&#xff1a;查看手册rm&#xff1a;删除网络命令ifconfig重定向 >>cat 查看文本文件clear清屏hi…

3.2 Bootstrap 下拉菜单(Dropdowns)

文章目录 Bootstrap 下拉菜单&#xff08;Dropdowns&#xff09;选项对齐标题 更多实例 Bootstrap 下拉菜单&#xff08;Dropdowns&#xff09; 本章将重点介绍 Bootstrap 下拉菜单。下拉菜单是可切换的&#xff0c;是以列表格式显示链接的上下文菜单。这可以通过与 下拉菜单&a…