3. 血缘分析的三大技术流派:解析式、日志式、标记式
做数据血缘分析,说白了就是搞清楚数据「从哪来、到哪去、中间经历了什么」。但实现这个目标的路子,业内主要有三条。我这些年踩过的坑,多半都跟选错路子有关。
今天咱们就把这三个流派掰开揉碎,看看它们各自怎么玩,有什么坑,适合什么场景。
一句话总结:解析式靠「读代码」,日志式靠「看记录」,标记式靠「贴标签」。没有银弹,只有最合适的组合。
3.1 解析式(SQL Parser)—— 最正统,但也最「娇气」
解析式,顾名思义,就是直接解析 SQL 语句。它把 SQL 文本拆成抽象语法树(AST),然后从树里提取表、字段、函数之间的依赖关系。
我个人习惯用这种流派做核心系统的血缘。为什么?因为它准。只要 SQL 能解析成功,血缘关系就是确定的,不需要猜。
3.1.1 工作原理
-- 示例:一条简单的 ETL SQL
INSERT INTO dws.daily_sales
SELECT
order_date,
product_id,
SUM(amount) AS total_amount
FROM ods.orders
WHERE status = 'completed'
GROUP BY order_date, product_id;
-- 解析器会提取出:
-- 目标表:dws.daily_sales(字段:order_date, product_id, total_amount)
-- 源表:ods.orders(字段:order_date, product_id, amount)
-- 过滤条件:status = 'completed'
-- 聚合操作:SUM(amount)
解析器内部会经历:词法分析 → 语法分析 → AST 构建 → 血缘提取。每一步都可能出问题。
3.1.2 优点与缺点
| 维度 | 说明 |
|---|---|
| 精度 | 极高。字段级血缘可以精确到列,甚至能识别表达式中的中间字段 |
| 实时性 | 好。SQL 提交就能解析,不需要等任务跑完 |
| 依赖 | 强。需要完整的 SQL 文本,且 SQL 必须符合语法规范 |
| 维护成本 | 高。不同方言(Hive SQL、Spark SQL、MySQL)需要不同的解析器 |
我曾经踩过的坑:有一次解析 Presto 的 SQL,里面用了大量的 WITH 子句和 LATERAL VIEW,解析器直接崩了。后来发现是 Presto 的语法扩展没覆盖到。所以,解析式对 SQL 方言的兼容性要求极高,别指望一个解析器打天下。
3.1.3 适用场景
- 数据仓库 ETL 任务:SQL 规范,变更频率低,适合做精确血缘
- 数据建模工具:如 dbt、DataForm,天然有 SQL 文本,解析成本低
- 数据质量监控:需要精确知道某个字段的来源,做影响分析
3.2 日志式(任务日志)—— 最通用,但最「粗糙」
日志式不碰 SQL,它只读任务运行日志。比如 Spark 的 Event Log、Hive 的 Job Log、Airflow 的 Task Log。从日志里提取「谁读了什么表、写了什么表」。
你想想看,很多老系统根本没有 SQL 文本,或者 SQL 被封装在存储过程里,解析器根本拿不到。这时候日志式就派上用场了。
3.2.1 工作原理
# 模拟一条 Spark 日志中的血缘信息
# 原始日志片段:
# 2024-01-15 10:23:45 INFO SparkContext:
# Registered input table: ods.orders (format: parquet)
# Registered output table: dws.daily_sales (format: parquet)
# Shuffle read: 2.3 GB
# Shuffle write: 1.1 GB
# 日志解析器会提取:
# 输入:ods.orders
# 输出:dws.daily_sales
# 数据量级:2.3 GB → 1.1 GB(可推算压缩比)
日志式不关心 SQL 怎么写,只关心「实际发生了什么」。所以它天然支持所有计算引擎,只要你能拿到日志。
3.2.2 优点与缺点
| 维度 | 说明 |
|---|---|
| 通用性 | 极强。Spark、Flink、Hive、MapReduce 都能用 |
| 精度 | 低。通常只能到表级,很难到字段级 |
| 实时性 | 差。必须等任务跑完才能拿到日志 |
| 存储成本 | 高。日志量大,长期存储需要规划 |
我的建议:日志式最适合做「血缘发现」—— 先通过日志把表级关系摸清楚,再针对关键链路用解析式做字段级细化。别一上来就想字段级,容易把自己累死。
3.2.3 适用场景
- 历史系统迁移:老系统没有 SQL 文档,日志是唯一线索
- 多引擎混用环境:Spark 做批处理、Flink 做流处理、Hive 做查询,统一用日志收口
- 数据资产盘点:先摸清有哪些表、谁在用,再决定要不要做精细血缘
3.3 标记式(数据打标)—— 最灵活,但最「人工」
标记式,说白了就是在数据产生的时候,主动打上「我是谁、我从哪来」的标签。比如在数据写入时,额外写一条元数据记录:「这条数据来自 ods.orders 的 order_id 字段」。
我记得有一次帮一家金融公司做血缘,他们的核心系统是 Cobol 写的,SQL 解析和日志解析都行不通。最后我们用了标记式,在数据接入层手动打标,反而效果最好。
3.3.1 工作原理
-- 标记式示例:在数据写入时主动记录血缘
-- 假设有一个血缘记录表 lineage_tags
INSERT INTO lineage_tags (
target_table,
target_field,
source_table,
source_field,
transform_rule,
etl_time
) VALUES (
'dws.daily_sales',
'total_amount',
'ods.orders',
'amount',
'SUM(amount) WHERE status = ''completed''',
CURRENT_TIMESTAMP
);
-- 数据本身不需要变,血缘信息单独存储
标记式的核心是「约定大于配置」。你需要定义一套标签规范,然后让开发者在写 ETL 时顺手打标。这听起来麻烦,但一旦形成习惯,血缘的准确率是最高的。
3.3.2 优点与缺点
| 维度 | 说明 |
|---|---|
| 精度 | 最高。只要打标规范,字段级、甚至记录级血缘都能实现 |
| 灵活性 | 最强。支持任意数据源、任意转换逻辑 |
| 人工成本 | 高。需要开发者配合,且容易遗漏 |
| 一致性 | 差。不同团队打标规范可能不一致 |
我曾经踩过的坑:有次团队为了省事,让开发者在代码里硬编码血缘标签。结果三个月后,代码重构了,标签没更新,血缘全乱了。标记式必须配套自动化校验机制,比如定期对比标签和实际 SQL 是否一致。
3.3.3 适用场景
- 非 SQL 数据源:如 API 接口、文件导入、消息队列
- 复杂转换逻辑:比如 Python 脚本里做了多层 DataFrame 操作,解析器和日志都搞不定
- 合规审计场景:需要精确到某条数据来自哪个上游系统,标记式最可靠
3.4 三大流派对比总览
为了方便你选型,我把三个流派的核心差异整理成了一张表。嗯,这张表我每次做咨询都会拿出来用。
| 维度 | 解析式 | 日志式 | 标记式 |
|---|---|---|---|
| 血缘粒度 | 字段级 | 表级(少数可到字段) | 字段级/记录级 |
| 准确率 | 高(语法正确时) | 中(依赖日志完整性) | 高(依赖打标规范) |
| 实时性 | 高(提交即解析) | 低(任务完成后) | 中(写入时打标) |
| 维护成本 | 高(方言适配) | 中(日志格式变化) | 高(规范管理) |
| 适用引擎 | SQL 类引擎 | 所有引擎 | 所有引擎 |
| 推荐场景 | 核心数仓 ETL | 血缘发现/盘点 | 合规审计/非 SQL 源 |
3.5 流派选择框架图
下面这张图是我自己总结的选型逻辑。你可以根据你的实际情况,沿着箭头找到最适合的流派。
3.6 我的实战建议
做了这么多年血缘,我最大的体会是:别追求一步到位。
我建议你分三步走:
- 先用日志式做全量扫描,花一周时间把公司所有任务的血缘摸清楚,哪怕只是表级。这一步能帮你发现 80% 的隐藏依赖。
- 再对核心链路用解析式做字段级细化。比如财务报表、用户画像这些关键数据,必须精确到字段。
- 最后用标记式补漏。那些解析器和日志都搞不定的「黑盒」任务,手动打标,并配套自动化校验。
一个小技巧:如果你用的是 Spark,可以同时用日志式(读 Event Log)和解析式(读 SQL 文本)。两者交叉验证,准确率能到 99% 以上。我之前的项目就是这么干的,效果出奇的好。
好了,三大流派就聊到这儿。记住,没有最好的流派,只有最适合你当前阶段的流派。选对了,事半功倍;选错了,后面全是坑。