元数据管理基础

聊到元数据,很多人的第一反应是——“不就是数据的数据吗?”
这话没错,但太笼统了。
我做了这么多年数据管道,见过太多人把元数据当成“附属品”,结果项目跑起来才发现,没有元数据,整个管道就是个黑箱。

说白了,元数据是数据的说明书、地图、日志本。
没有它,你连数据从哪来、怎么用、靠不靠谱都说不清。

一句话总结:元数据管理是数据管道的“神经中枢”。
它不直接处理业务数据,但它决定了业务数据能被多好地处理。

什么是元数据

元数据就是“关于数据的数据”。
举个例子,一张销售订单表:

  • 表名、字段名、字段类型 —— 这是技术元数据
  • 这个字段代表“客户ID”,那个字段是“订单金额” —— 这是业务元数据
  • 这张表什么时候被更新过,谁跑了ETL,跑了多久 —— 这是操作元数据

你看,同样一张表,从三个角度看,信息完全不同。
我以前有个项目,团队二十多人,各管各的字段命名。
有人叫 cust_id,有人叫 customer_number,还有人写 cid。
结果联调的时候,光对齐字段就花了两周。
这就是没管好元数据的反面教材。

三大元数据分类

业内一般把元数据分成三类:技术元数据、业务元数据、操作元数据。
你想想看,这其实对应了数据的三个关键问题:

  • 它是什么? —— 技术元数据告诉你数据结构
  • 它什么意思? —— 业务元数据告诉你业务含义
  • 它怎么来的? —— 操作元数据告诉你数据生命周期

我习惯用一张表来区分它们:

分类 定义 示例 典型场景
技术元数据 描述数据系统的技术细节 表结构、字段类型、索引、分区键 数据建模、数据迁移、ETL开发
业务元数据 描述数据的业务含义和规则 字段业务定义、数据字典、计算逻辑 报表开发、数据治理、业务分析
操作元数据 记录数据处理过程的运行信息 作业运行日志、调度时间、错误记录 管道监控、故障排查、审计追溯

我个人认为,这三类元数据缺一不可。
技术元数据是骨架,业务元数据是血肉,操作元数据是脉搏。

技术元数据详解

技术元数据是最“硬”的那一类。
它直接反映了底层系统的实现细节。比如:

  • 数据库的表名、列名、数据类型、约束
  • 文件存储的路径、格式(Parquet、Avro、CSV)
  • ETL脚本的输入输出、依赖关系
  • API的端点、请求参数、响应结构

小技巧:技术元数据最好从源头自动采集。
我一般用information_schema或DESCRIBE语句来捞取表结构,然后存到元数据仓库里。
手工维护?别想了,你根本追不上变更的速度。

举个例子,在PostgreSQL里获取表的元数据:

SELECT
    table_name,
    column_name,
    data_type,
    is_nullable,
    character_maximum_length
FROM information_schema.columns
WHERE table_schema = 'public'
ORDER BY table_name, ordinal_position;

输出是这样的:

 table_name | column_name | data_type | is_nullable | character_maximum_length
------------+-------------+-----------+-------------+--------------------------
 orders     | order_id    | integer   | NO          |
 orders     | customer_id | integer   | NO          |
 orders     | order_date  | date      | NO          |
 orders     | amount      | numeric   | YES         |

你看,这就是最原始的技术元数据。
有了它,你在写ETL时就清楚每个字段的类型、能否为空。
我曾经因为没检查is_nullable,跑了一段处理NULL值的逻辑,结果字段是NOT NULL的……
那个bug查了我整整半天。

业务元数据详解

业务元数据,说白了就是“这个数据在业务里到底代表什么”。
它不关心字段类型,关心的是业务含义。

比如:

  • order_status = 'P' 代表“已付款”还是“待处理”?
  • amount 是含税金额还是不含税?
  • 这个报表的“活跃用户”是怎么定义的——7天内登录过?还是30天内有过交易?

如果没有业务元数据,技术团队和业务团队就像在说不同的语言。
我记得有一次,财务部门要统计“本月退款金额”,但开发那边认为“退款”是amount < 0的记录。
结果财务说:不对,我们的退款是单独一张退款表,不是负值订单。
这就是业务元数据没对齐的典型例子。

注意:业务元数据最难管理。
它不是从系统里自动捞出来的,而是靠人去定义和维护。
我建议用数据字典来记录,并且要定期评审。

一个简单的业务元数据记录格式:

字段名: order_status
业务定义: 订单当前状态
可选值:
  - P: 已付款(Payment completed)
  - S: 已发货(Shipped)
  - D: 已送达(Delivered)
  - C: 已取消(Cancelled)
备注: 由订单系统维护,ETL不做转换
负责人: 张三(订单研发组)
更新日期: 2024-01-15

操作元数据详解

操作元数据就是“数据管道的运行日志”。
它记录了谁、在什么时候、做了什么、结果如何。

常见内容:

  • ETL作业的启动时间、结束时间、耗时
  • 处理的数据行数、成功/失败记录数
  • 错误信息、重试次数、告警记录
  • 数据血缘——这张表的记录是从哪张表来的

操作元数据最大的价值在于可追溯。
举个例子,你今天发现报表上的数据不对。
如果能查操作元数据,就可以回答:

  • 昨天的ETL跑了吗?
  • 跑的时候有没有报错?
  • 是不是某个上游表没更新?

我曾经因为没记录操作元数据,出过一次大问题。
某个财务报表连续三天数据异常,但没人知道原因。
因为没有日志,只能人肉排查。
后来发现是上游一个API改了返回格式,但ETL没有做校验。
从那以后,我每个管道都会加上操作元数据的埋点。

建议:操作元数据最好用结构化格式存储,比如JSON或表格。
这样后续查询和分析都很方便。

一条典型的操作元数据记录:

{
  "job_name": "etl_daily_sales",
  "run_id": "run_20240115_030000",
  "start_time": "2024-01-15 03:00:00",
  "end_time": "2024-01-15 03:12:47",
  "status": "success",
  "rows_read": 128450,
  "rows_written": 128450,
  "errors": [],
  "dependencies": ["source_orders", "source_customers"],
  "output_tables": ["dw_fact_sales"]
}

元数据分类的价值

说了这么多,为什么要费劲去区分三类元数据?

因为不同的角色关注点不同:

  • 数据工程师 关心技术元数据:表结构、分区、文件格式
  • 数据分析师 关心业务元数据:字段含义、计算口径
  • 运维人员 关心操作元数据:作业状态、运行耗时

如果混在一起管理,谁都找不到需要的信息。
分类之后,每个角色都能快速定位到自己关心的内容。

下面这张图展示了三类元数据的关系:

元数据分类结构图 元数据存储库 技术元数据 表结构/字段 文件格式 业务元数据 数据字典 计算口径 操作元数据 运行日志 数据血缘 三类元数据共同构成完整的数据描述 技术元数据:数据结构与存储 业务元数据:数据含义与规则 操作元数据:数据生命周期与运行状态

嗯,这就是元数据管理的基础。
技术、业务、操作——三个维度,一个都不能少。
理解了这些分类,后面搭建元数据管道时,你才知道该采集什么、存什么、给谁用。

我个人建议,从技术元数据入手。
因为它最好自动化采集,能快速看到成效。