从原理到实践:深度解析Skill与Rule的核心区别及适用场景

3次阅读
没有评论

共计 1950 个字符,预计需要花费 5 分钟才能阅读完成。

image.webp

概念澄清:当策略模式遇上控制反转

刚开始接触规则引擎时,我也曾被 Skill 和 Rule 这两个概念搞得一头雾水。直到某天调试优惠券叠加 bug 时突然想通:Rule 就像策略模式里的具体算法,而Skill 更像是 Spring 框架里的 Bean 容器。举个例子:

从原理到实践:深度解析 Skill 与 Rule 的核心区别及适用场景

  • Rule 的原子性 :就像策略接口的execute() 方法,必须完整执行且不依赖外部状态。比如风控规则:

    rule "未成年禁止购买酒精"
      when
        $order : Order(customer.age < 18, containsAlcohol())
      then
        reject("AGE_LIMIT_FAIL");
    end

  • Skill 的上下文感知 :类似@Service 注解的类,可以持有运行时状态。比如优惠券引擎:

    @Skill(priority = VIP_USER)
    public class CouponSkill {
      private List<Coupon> activeCoupons; // 维持优惠券状态
    
      @Action
      void apply() {// 能访问用户历史订单等上下文}
    }

实现对比:看 Drools 和 EasyRules 如何分道扬镳

在 Drools 的 Rete 算法实现中,Rule 会被编译成如下伪代码结构:

// Rule 编译结果
AlphaNode1 -> BetaNode2 -> TerminalNode

而 EasyRules 对 Skill 的处理更简单粗暴:

// EasyRules 的 Skill 执行流程
for (Skill skill : skills) {if (skill.evaluate(ctx)) { // 上下文评估
    skill.execute(ctx);      // 带状态执行
    break;                   // 通常首个匹配即终止
  }
}

关键差异在于:Rule 的节点会参与 Rete 网络共享,而Skill 通常独立评估。这导致在 Drools 中混用两者时可能出现诡异的性能问题。

场景适配:电商案例的 AB 面

优惠券叠加(Skill 模式)

@Skill(name="coupon", priority=3)
public class DiscountSkill {
  @Condition
  public boolean isApplicable(@Fact User user) {return user.getLevel() > VIP_LEVEL;
  }

  @Action
  public void apply(@Fact Order order) {order.applyCoupon("VIP2024"); // 修改订单状态
  }
}

反欺诈规则链(Rule 模式)

rule "同 IP 高频下单"
  salience 10
  when
    $stats : IpStats(frequency > 50)
    $order : Order(ip == $stats.ip)
  then
    insert(new FraudMark("IP_RISK"));
end

rule "午夜异常交易"
  salience 20
  when
    $order : Order(hour > 23 || hour < 5)
  then
    insert(new FraudMark("NIGHT_RISK"));
end

性能陷阱:Rete 网络的隐藏成本

我曾犯过一个典型错误:把本应是 Skill 的会员等级判断写成 Rule,导致每笔订单都要重复计算相同的用户等级。优化方案是:

// 错误写法 - 每个订单独立评估
rule "GoldUserRule" when
  $user : User(level == "GOLD")
  $order : Order(user == $user)

// 正确写法 - 共享 AlphaNode
rule "CacheUserLevel" when
  $user : User()
then
  insert(new UserLevelCache($user));
end

rule "GoldUserOptimized" when
  $cache : UserLevelCache(level == "GOLD")
  $order : Order(user == $cache.user)

生产实践的三个锦囊

  1. 决策表分离术
  2. 业务规则用 Excel 决策表管理
  3. 技术规则 (如超时控制) 硬编码实现

  4. Skill 拆分时机

  5. 当需要独立单元测试时
  6. 当执行耗时超过 500ms 时
  7. 当需要复用相同条件判断时

  8. 监控指标设计

    # Rule 执行指标
    rule_engine_rule_exec_time{name="fraud_check"} 0.23
    
    # Skill 状态指标
    rule_engine_skill_state{name="coupon", attribute="active_coupons"} 5

开放式思考题

在 Serverless 的冷启动环境下,Skill 如果维持状态可能导致严重的性能抖动。但若完全无状态,又可能失去上下文感知的优势。或许可以参考 Lambda 的 Execution Context 设计,采用分层的状态管理策略?这个平衡点值得深入探讨。

正文完
 0
评论(没有评论)