2、血缘元数据模型:表级血缘、字段级血缘、ETL过程血缘、血缘的粒度与层次

聊完了血缘分析的价值,咱们得落地了。落地第一步,就是搞清楚血缘数据长什么样——也就是元数据模型。

我见过不少团队,一上来就急着画血缘图,结果连「表跟字段的关系」都没理清,画出来的图根本没法用。说白了,血缘元数据模型就是给数据关系「建档案」。档案建得细,后面查问题才快。

2.1 表级血缘:最粗的粒度

表级血缘,看的是表与表之间的依赖关系。比如一张报表数据来自哪几张源表,或者一张中间表被哪些下游表引用。

我个人习惯把表级血缘比作「数据地图上的城市」。你不需要知道城市里每条街怎么走,但得知道A城市到B城市有路。

表级血缘的核心要素:

  • 源表:数据从哪里来
  • 目标表:数据往哪里去
  • 依赖方向:上游→下游
  • 调度批次:T+1、实时等

举个例子,一个典型的数仓分层:

ODS.order_info  →  DWD.dwd_order_detail  →  DWS.dws_order_daily  →  APP.rpt_order_summary

这就是一条表级血缘链。你看到APP层报表数据有问题,顺着这条链往上查,很快就能定位到ODS层还是DWD层出了岔子。

我在项目中遇到过,有个同事排查数据延迟,从APP层一路查到ODS层,花了整整两天。后来我帮他搭了表级血缘图谱,再出问题,鼠标点两下就定位到了。嗯,这就是建模的价值。

2.2 字段级血缘:精细到细胞

表级血缘能告诉你「哪张表影响了哪张表」,但很多时候这还不够。比如某个金额字段算错了,你得知道这个字段是从源表的哪个字段来的、经过了什么转换。

字段级血缘,说白了就是「字段到字段」的映射关系。它比表级血缘精细得多,也复杂得多。

维度 表级血缘 字段级血缘
粒度 表 字段
复杂度 低 高
存储量 小 大(可能大10倍以上)
典型场景 链路追踪、影响分析 字段溯源、口径对齐
维护成本 低 高(需解析SQL)

字段级血缘怎么存?我建议至少记录这几个属性:

  • 源字段:如 ods.order_info.pay_amount
  • 目标字段:如 dwd.dwd_order_detail.pay_amt
  • 转换逻辑:如 COALESCE(pay_amount, 0)
  • 表达式类型:直接映射、函数转换、条件判断

我的经验:字段级血缘的解析,核心是SQL解析器。别自己从头写,用开源的 sqlparse(Python)或 ANTLR 生成的语法树来解析,省时省力。我曾经手写过一次解析器,踩了无数坑,后来老老实实换了开源方案。

2.3 ETL过程血缘:把「怎么变的」记下来

表级和字段级血缘,更多是描述「数据是什么」。但数据不会自己变,它得经过ETL过程。ETL过程血缘,记录的就是「数据是怎么变的」。

你想想看,一个字段从源表到目标表,中间可能经历了:

  1. 从A表JOIN B表
  2. 过滤掉状态为0的记录
  3. 对金额做四舍五入
  4. 聚合求和

每一步都可能引入问题。ETL过程血缘,就是把每一步的算子、参数、输入输出都记录下来。

注意:ETL过程血缘的存储量非常大。一个复杂的ETL任务,可能产生上千个算子节点。我建议只记录关键算子(JOIN、FILTER、AGGREGATE、UNION),不要事无巨细全记,否则存储和查询都会爆炸。

ETL过程血缘的典型结构:

{
  "job_id": "etl_dwd_order_001",
  "job_type": "SPARK_SQL",
  "operators": [
    {
      "op_id": "op_001",
      "op_type": "TABLE_SCAN",
      "input_table": "ods.order_info",
      "output_fields": ["order_id", "pay_amount", "status"]
    },
    {
      "op_id": "op_002",
      "op_type": "FILTER",
      "condition": "status = 1",
      "input_op": "op_001"
    },
    {
      "op_id": "op_003",
      "op_type": "AGGREGATE",
      "group_by": ["order_id"],
      "agg_func": "SUM(pay_amount)",
      "input_op": "op_002",
      "output_table": "dwd.dwd_order_detail"
    }
  ]
}

有了这个过程血缘,哪天数据对不上了,你可以回放整个ETL流程,看看是哪一步出了问题。我曾经靠这个定位过一个Bug——一个FILTER条件写反了,导致过滤掉了90%的数据。如果没有过程血缘,这种问题查起来简直是大海捞针。

2.4 血缘的粒度与层次:怎么选?

讲到这里,你可能会问:那我到底该用哪种粒度?

答案是:看场景。不同场景需要不同粒度的血缘。

场景 推荐粒度 原因
数据链路监控 表级 快速定位哪张表延迟或失败
字段口径对齐 字段级 精确知道字段来源和转换逻辑
ETL故障排查 过程级 回放每一步,定位具体算子
影响分析(上游变更) 表级+字段级 先看表级影响范围,再看字段级细节
数据质量稽核 字段级+过程级 需要知道字段的完整加工链路

我个人建议,起步阶段先做表级血缘,成本低、见效快。等团队成熟了、工具链完善了,再逐步上字段级和过程级。别一上来就想搞大而全,容易烂尾。

2.5 血缘层次模型:一张图看懂

下面这张图,是我梳理的血缘元数据层次模型。它把表级、字段级、ETL过程级的关系串在了一起。

血缘元数据层次模型 表级血缘(Table-Level) 记录表与表之间的依赖关系 示例:ODS.order_info → DWD.dwd_order_detail → DWS.dws_order_daily 粒度:粗 | 存储量:小 | 适用:链路监控、影响分析 字段级血缘(Column-Level) 记录字段与字段之间的映射关系 示例:ods.order_info.pay_amount → COALESCE(pay_amount,0) → dwd.dwd_order_detail.pay_amt 粒度:细 | 存储量:中 | 适用:字段溯源、口径对齐 ETL过程血缘(Process-Level) 记录数据加工过程中的每个算子 示例:TABLE_SCAN → FILTER(status=1) → AGGREGATE(SUM) → WRITE 粒度:最细 | 存储量:大 | 适用:ETL故障排查、数据质量稽核 💡 层次关系说明: 上层(表级)为下层(字段级、过程级)提供上下文;下层为上层提供细节支撑。 实际应用中,三层血缘协同工作,才能完整追溯数据问题。

这张图想表达的核心思想是:三层血缘不是互斥的,而是互补的。表级血缘给你「全局地图」,字段级血缘给你「街道详情」,ETL过程血缘给你「交通摄像头记录」。三者结合,才能真正做到数据问题可追溯。

总结一下:

  • 表级血缘:快速定位「哪张表」出了问题
  • 字段级血缘:精确找到「哪个字段」、怎么来的
  • ETL过程血缘:回放「每一步」加工,定位具体算子
  • 粒度选择:从粗到细,逐步建设,别贪多