如何设计一个规则引擎

产品设计过程当中,经常会遇到需要制定各种规则的场景,例如如何选择承运商、如何匹配费用等等。这里记录下关于这种面向用户配置的规则引擎设计的思考。

本质

将 IF 或 CASE 的条件与结果可配置化,UI 化或结构化(使用 json\SQL)如下内容:

  1. 对象
  2. 比较运算符
  3. 逻辑运算符 与 或 非
  4. 计算顺序
  5. 代码执行顺序
  6. 结果

对象

数据库字段、实体类属性在前台对应业务属性的映射。

  1. 通常需要决定那些实体类,哪些属性可以用于制定规则。如果将这个也变成自由定义,可能会过度增加复杂度。
  2. 可能会遇到多个对象进行数学计算过后再进行比较运算的情形,例如体积满足某个条件,但是数据库只单独记录了长、宽、高,在设计时需要额外注意。
  3. 前台设计时,应该使用下拉框,避免输入。

比较运算符

  1. 使用下拉框。
  2. 支持常见的数值型运算符和字符串运算符。
  3. 如果对象选择是数值型的属性,那么运算符应该候选项限定为数值运算符。
  4. 尽量不使用 isNull 之类的运算符,不太适合暴露给普通用户。

如果对象是数值型,在前台进行输入合法验证。

逻辑运算符 与 或 非

  1. AND OR NOT 且 或 非。
  2. 使用下拉框。

计算顺序

  1. 自然顺序,不需要设计。
  2. 自定义顺序,需要使用括号。
  3. 用户可能很容易理解括号,但是不一定能够记得其他运算符的先后顺序,可能的话,将用户配置的规则的计算顺序在前台展示出来。

代码执行顺序

  1. 可以将 CASE WHEN THEN ELSE 或 IF THEN ELSE 这样的关键字或对应的关键字中文描述暴露给用户,如果确定用户可以理解的话。
  2. 使用规则优先级数字,交由用户填写。
    1. 应该提示给用户,数字大小与执行顺序的关系。
    2. 规则应该按照执行顺序进行排序。
    3. 如果 UI 设计上,不同条目的规则不可以拖拽进行优先级调整,那么优先级应该选择数值型,以便插入规则时不需要修改后续所有规则。
  3. 如果规则已经使用整数型作为数据类型,在配置时可以使用 100,200 这样的大间距整数,当需要插入新规则时,取前后规则的中间值即可,而不需要调整所有后续规则。
  4. 对优先级进行唯一性检查。
  5. 注意这些分支语句都应该有兜底。

结果

问题

新增一条规则后,怎么知道规则逻辑对不对?

可以在规则引擎的配置页面增加一个测试功能,允许用户使用某个历史数据验证匹配的具体规则来验证,也可以允许用户手动输入测试的各属性值的组合来验证。

新增一条规则后,可以验证该命中规则的命中了,怎么确保不该命中规则不命中呢?

每次规则被更新,都选择历史一段时期的数据重新匹配一次规则,并输出和之前匹配的目标结果不一致的数据,交给用户验证。

规则太多,管理困难,新增编辑规则时,完全不知道相关的规则有哪些,优先级应该如何制定

  1. 规则太多就 divide and conquer,看看规则是不是可以明显的进行分组,把最常用的区别大的因素作为规则头的判定对象,其他的作为明细的判定对象。如此一来只需要在组内的少数规则中判断如何设置优先级即可。
  2. 每次新增规则后,采取历史数据回归验证的方式检查正确性。

好的实践

  1. 记录命中规则的原因与结果。
  2. 使用缓存机制。如果规则长期稳定,使用缓存可以避免遍历规则。例如使用重量、体积范围决定承运商的规则,可以记录下来相同重量体积区间的记录,避免重复计算。
  3. 每条规则鼓励用户填写规则描述,用直白的语言便于事后理解与核对规则设定是否满足意图。
  4. 注意规则应用的场景是否经常有时间段限制,如果有,允许用户配置生效时间范围。对于时间要求高的场景,不能寄希望于用户在时间点到达那一刻再去配置规则,必须要提前配置。有时间段限制的规则,需要考虑规则延期或制定新规则的提前期,必须在提前期前提醒用户开始未来时间段规则的制定。
  5. 规则使用版本号,修改应该记录下修改前后的内容日志,用于事后溯源。
  6. 对生产环境影响很大而且破坏不可逆的规则,应该提前考虑如何在测试环境对线上的数据进行模拟。
  7. 对规则设定是否启用的开关,并且应该提供规则不生效时,如何达到原目标的替代方案。
  8. 一个规则可能会出于管理考虑需要人工选中规则输出结果,设计时需要考虑。例如:
    1. 计费规则,使用去年的业务数据,运行一次今年的新报价计费规则对比
    2. 同样的业务数据,分别使用不同供应商的规则,进行结果对比

我所说的一切都只是我的观点。
我的观点都可能是错的。

访问量统计:0

Licensed under CC BY-NC-SA 4.0
最后更新于 Sep 25, 2025 18:58 +0800
发表了8篇文章 · 总计19.05k字
输出促进思考
Built with Hugo
主题 StackJimmy 设计