easy rule 学习记录

文章介绍了两种规则执行方式,一种是非注解方式,另一种是基于InferenceRulesEngine的循环执行方式。规则引擎包括DefaultRulesEngine和InferenceRulesEngine,前者在遇到特定条件时可跳出规则执行,后者会持续执行直到所有规则的条件都不满足。规则的触发和评估涉及监听器机制,并支持CompositeRule和根据Facts动态选择规则。此外,还提到了通过YML配置自动生成RuleGroup的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

总体:

使用方面除了官网的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 执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_40455124

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值