4. 数据质量规则引擎的设计与落地

数据质量规则引擎是数据治理体系中的“执行中枢”。它把散落在文档、口头约定和临时 SQL 中的校验逻辑,抽象为可配置、可复用、可版本化、可调度的规则资产,并在批处理和流处理两类场景中统一执行。规则引擎设计得好不好,直接决定了数据质量监控是“事后救火”还是“事前拦截”。本节围绕规则分类、规则模板化、动态阈值、规则版本管理以及批流执行策略五个核心问题展开。

一、规则分类:先分清“查什么”和“怎么查”

规则分类是引擎设计的第一步。实践中通常从两个维度切分:校验对象维度和校验语义维度。校验对象维度回答“规则作用在什么上”,包括表级、字段级、跨表级、跨系统级;校验语义维度回答“规则在判断什么”,包括完整性、唯一性、有效性、一致性、及时性、准确性。

把两个维度交叉,就能得到一张规则分类矩阵。例如“字段级 + 完整性”对应非空校验;“字段级 + 有效性”对应枚举值域校验;“表级 + 唯一性”对应主键重复检测;“跨表级 + 一致性”对应主外键引用完整性;“跨系统级 + 一致性”对应源端与目标端的行数、金额汇总比对。分类的价值在于:每一类规则对应一种执行算子、一种阈值策略和一种告警级别,避免把“非空校验”和“跨系统对账”混在同一套参数体系里。

二、规则模板化:从“写 SQL”到“填参数”

如果每条规则都靠手写 SQL 维护,规则数量一多就会失控。规则模板化的核心思路是:把同类规则的 SQL 骨架固化为模板,把表名、字段名、阈值、过滤条件等抽成参数,用户只需填写参数即可实例化一条规则。

以非空率校验为例,模板可以定义为:

模板ID: TPL_NOT_NULL_RATE
语义: 字段非空率 = 非空行数 / 总行数
参数:
  table_name   目标表
  column_name  目标字段
  filter_cond  过滤条件(可选,默认 1=1)
  threshold    非空率下限,如 0.98
生成SQL:
  SELECT COUNT(*) AS total,
         COUNT(column_name) AS not_null_cnt,
         COUNT(column_name) * 1.0 / COUNT(*) AS rate
  FROM table_name
  WHERE filter_cond
判定: rate >= threshold 则通过

模板化带来三个直接收益:一是规则可批量生成,新增一张表只需实例化若干模板;二是执行逻辑统一,避免不同人写出语义不一致的 SQL;三是模板本身可以版本化,修改模板即影响所有实例,便于统一升级。需要注意的是,模板参数必须做白名单校验,防止表名、字段名被注入恶意内容。

三、动态阈值:让规则适应数据本身的波动

固定阈值在业务量波动时会频繁误报。例如某表日均订单量 10 万,周末降到 6 万,若把“日行数不低于 8 万”写死,周末必然告警。动态阈值的做法是:基于历史数据计算基线,再结合波动幅度设定上下界。

常用方法有三种。第一种是移动平均 + 标准差:取过去 N 天(如 14 天)的行数,计算均值 μ 和标准差 σ,阈值设为 μ ± kσ,k 通常取 2 或 3。第二种是同环比:与上周同一天、上月同一天比较,偏离超过一定百分比才告警,适合有明显周期性的数据。第三种是分位数法:取历史数据的 P5 和 P95 作为下界和上界,对非正态分布更稳健。

动态阈值不是完全放开,而是“基线自动算、边界人工确认”。建议对每条动态阈值规则保留最近一次计算出的基线值和实际值,便于回溯为什么触发或为什么没触发。

四、规则版本管理:规则也是代码

规则一旦上线就会影响生产判断,必须像代码一样管理版本。每条规则应记录:规则ID、模板ID、参数快照、生效时间、失效时间、创建人、变更原因。当规则被修改时,不覆盖原记录,而是生成新版本,旧版本标记为失效但保留历史。

版本管理要解决三个问题:一是可追溯,某天告警突然增多,能查到是不是前一天改了阈值;二是可回滚,新版本误报严重时能快速切回旧版本;三是可对比,同一规则不同版本在同一份数据上的判定结果可以并行跑,评估变更影响。建议规则版本号采用“主版本.次版本”形式,主版本表示语义变化(如从非空率改为唯一率),次版本表示参数调整(如阈值从 0.98 调到 0.95)。

五、批流场景中的执行策略

批处理和流处理对规则引擎的要求不同。批处理场景数据量大、可容忍分钟级延迟,适合做全量扫描、跨表关联、复杂聚合;流处理场景要求毫秒到秒级响应,适合做单条或微批的即时校验,如非空、格式、枚举值域。

执行策略上建议分层:流处理层负责“入口拦截”,对写入消息做轻量规则校验,不通过的直接进死信队列;批处理层负责“离线体检”,对落库后的全量数据做完整性、一致性、跨表对账等重规则。两层共用同一套规则元数据和模板,但执行算子不同。流处理层只加载标记为“实时”的规则,批处理层加载全部规则。

下面这张图展示了规则引擎从规则定义到批流双路执行的完整结构关系:

规则定义层 规则分类 表级/字段级/跨表级 规则模板 SQL骨架+参数 动态阈值 μ±kσ / 同环比 版本管理 主版本.次版本 规则实例 参数快照 规则元数据仓库 规则ID · 模板ID · 参数 · 版本 · 生效时间 · 标签 规则执行引擎 规则解析 · 算子调度 · 阈值判定 · 结果输出 流处理执行路径(实时) 加载标签=实时 的规则 单条/微批校验 非空·格式·枚举 不通过→死信队列 秒级响应 批处理执行路径(离线) 加载全部规则 全量扫描·聚合 跨表·对账 分钟级延迟 T+1 体检报告 质量结果库 · 告警 · 基线回溯 · 版本对比 版本变更写入元数据

图中可以看到,规则定义层产出的规则实例统一写入元数据仓库,执行引擎从元数据仓库加载规则后,按标签分流到流处理和批处理两条路径,最终结果汇聚到质量结果库。版本管理通过虚线回环,把规则变更重新写回元数据,形成闭环。

六、落地时的几个关键判断

第一,规则不是越多越好。每条规则都有执行成本和误报成本,建议按“影响面 × 发生概率”排序,优先上线高影响、高概率的规则。第二,阈值要留观察期。新规则上线后先只告警不拦截,观察一到两周,确认误报率可接受后再切换为拦截。第三,批流规则要避免重复告警。同一条规则如果既在流处理层又在批处理层执行,需要设置去重窗口,否则同一条脏数据会触发两次告警。第四,规则模板要定期评审。业务变化后,旧模板可能不再适用,应结合版本管理做定期清理和升级。

规则引擎的成熟度可以用一个简单指标衡量:新增一张表的监控,需要写多少行 SQL。如果答案是零,只需要填参数,说明模板化和元数据管理已经到位。