2. 血缘追踪的元数据基础:分类与存储选型

做特征血缘追踪,第一步不是写代码,而是搞清楚——元数据到底该怎么管。

我见过不少团队,一上来就急着搭血缘解析引擎,结果跑了两周发现:字段对不上、表找不到、上下游关系全乱套。为什么?因为元数据本身就没理清楚。说白了,血缘追踪的根基就是元数据。元数据乱了,血缘就是空中楼阁。

核心观点:血缘追踪的质量,不会超过它所依赖的元数据的质量。元数据治理是血缘追踪的“地基工程”。

2.1 元数据的两种面孔:技术 vs 业务

元数据分类的方式很多,但在血缘场景下,我习惯把它分成两大类:技术元数据和业务元数据。这两者缺一不可。

2.1.1 技术元数据

技术元数据描述的是“数据长什么样、存在哪里、怎么流动”。它是血缘追踪的骨架。

  • 表结构信息:库名、表名、字段名、字段类型、分区键、主键、外键。
  • 存储信息:文件格式(Parquet/ORC/Avro)、存储路径、压缩方式、数据量大小。
  • ETL 作业信息:SQL 脚本、调度任务、输入输出映射、执行频率。
  • 数据质量信息:空值率、唯一性约束、数据新鲜度、校验规则。
  • 访问日志:谁在什么时间、通过什么方式读取了哪些数据。

举个例子。我在项目中遇到过这样一个坑:某个特征表每天凌晨 3 点由 Spark 任务产出,但下游的实时特征服务在凌晨 2 点就开始读取。结果呢?服务读到的全是前一天的老数据。这就是技术元数据里缺少了数据新鲜度和产出时间窗口的标注。后来我们在元数据里加上了 data_available_time 字段,才彻底解决这个问题。

2.1.2 业务元数据

业务元数据描述的是“数据代表什么、谁在用、有什么含义”。它是血缘追踪的灵魂。

  • 业务定义:字段的业务含义、计算口径、枚举值说明。
  • 数据所有者:谁负责这个表、谁是数据管家、谁是数据消费者。
  • 数据分级分类:是否包含 PII(个人身份信息)、敏感等级、合规要求。
  • 使用场景:这个特征用于哪个模型、哪个报表、哪个业务决策。
  • 变更历史:字段含义变更记录、口径调整说明、废弃时间。

你想想看,如果血缘追踪只记录技术层面的字段映射,却不知道某个字段是“用户近 30 天消费金额”还是“用户近 30 天消费次数”,那这个血缘图对业务人员来说就是一堆乱码。我曾经在一个金融风控项目里,就因为业务元数据缺失,导致模型上线后才发现特征口径对不上——整整回滚了两周。

维度 技术元数据 业务元数据
关注点 数据怎么存、怎么算、怎么流 数据代表什么、谁在用、怎么用
典型用户 数据工程师、平台工程师 数据分析师、业务产品、合规
血缘追踪中的作用 提供字段级映射、作业依赖、存储路径 提供字段含义、使用场景、变更影响分析
常见存储 Hive Metastore、关系型数据库 图数据库、文档数据库、数据目录工具

我的建议:不要试图一次性把两类元数据都做到完美。先搞定技术元数据,让血缘能跑通;再逐步补充业务元数据,让血缘能看懂。分步走,比一步到位更现实。

2.2 元数据存储选型:没有银弹

选存储引擎这件事,我踩过不少坑。不同的元数据类型,适合不同的存储方案。下面是我个人比较常用的三种选型思路。

2.2.1 MySQL:适合结构化元数据

MySQL 适合存储结构化、关系明确、变更不频繁的元数据。比如表结构信息、字段定义、作业配置等。

优点很明显:成熟稳定、事务支持、查询灵活。缺点也很突出:不适合处理复杂的多跳关系。比如你要查“这个字段最终影响了哪些下游特征”,用 MySQL 写递归 JOIN,性能会非常难看。

-- 一个典型的元数据表设计示例
CREATE TABLE feature_metadata (
    feature_id      BIGINT PRIMARY KEY AUTO_INCREMENT,
    feature_name    VARCHAR(255) NOT NULL,
    database_name   VARCHAR(128),
    table_name      VARCHAR(128),
    column_name     VARCHAR(128),
    data_type       VARCHAR(64),
    owner           VARCHAR(128),
    created_at      TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at      TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_feature_name (feature_name),
    INDEX idx_table (database_name, table_name)
);

嗯,这里要注意:MySQL 做元数据存储时,一定要做好索引规划。我见过一个团队,元数据表里几百万条记录,查询一次要十几秒,就是因为没建索引。后来加了联合索引,查询时间降到了毫秒级。

2.2.2 Neo4j:适合血缘关系网络

Neo4j 是图数据库,天生适合存储多对多、多跳、网状关系的数据。血缘追踪本质上就是一个有向无环图(DAG),用图数据库来存,再合适不过。

我记得第一次用 Neo4j 做血缘追踪时,被它的查询效率惊艳到了。一个 6 层深度的上游溯源查询,MySQL 要跑 3 秒,Neo4j 只要 50 毫秒。差距就在这里。

// Neo4j 血缘关系建模示例
// 创建节点:表、字段、作业
CREATE (t:Table {name: "user_profile", database: "ods"})
CREATE (c:Column {name: "user_id", type: "bigint"})
CREATE (j:Job {name: "etl_user_features", schedule: "daily"})

// 创建关系:字段属于表、作业产出表
CREATE (c)-[:BELONGS_TO]->(t)
CREATE (j)-[:PRODUCES]->(t)

// 血缘查询:查找某个字段的所有上游
MATCH (c:Column {name: "user_id"})<-[:PRODUCES|:DERIVED_FROM*]-(upstream)
RETURN upstream

避坑指南:我曾经在一个项目中,把所有元数据一股脑全塞进 Neo4j,包括表结构、字段类型、存储路径等结构化信息。结果图数据库的存储效率远不如 MySQL,查询也变得臃肿。后来我调整了策略:关系用 Neo4j,属性详情用 MySQL,两者通过 ID 关联。这样既保留了图查询的灵活性,又保证了结构化数据的存储效率。

2.2.3 Hive Metastore:大数据生态的元数据中心

如果你的数据湖基于 Hive 或 Spark,那 Hive Metastore 几乎是绕不开的选择。它天然存储了 Hive 表、分区、字段、存储格式等元数据。

Hive Metastore 的底层存储通常是 MySQL 或 PostgreSQL,但上层提供了统一的 Thrift 接口。这意味着你可以通过 HiveMetaStoreClient 直接获取表结构信息,而不需要自己再维护一套元数据采集逻辑。

// 通过 Hive Metastore Client 获取表元数据
import org.apache.hadoop.hive.metastore.HiveMetaStoreClient;
import org.apache.hadoop.hive.metastore.api.Table;

HiveMetaStoreClient client = new HiveMetaStoreClient(conf);
Table table = client.getTable("default", "user_features");

// 获取字段信息
List<FieldSchema> fields = table.getSd().getCols();
for (FieldSchema field : fields) {
    System.out.println(field.getName() + " : " + field.getType());
}

// 获取分区信息
List<FieldSchema> partitionKeys = table.getPartitionKeys();
for (FieldSchema pk : partitionKeys) {
    System.out.println("Partition: " + pk.getName());
}

但要注意,Hive Metastore 只存储技术元数据,不存储业务元数据。而且它不支持图查询,做多跳血缘分析时,需要自己在外层做关系拼接。

存储方案 适合场景 不适合场景 我个人的推荐指数
MySQL 结构化元数据、变更管理、事务场景 复杂多跳关系、大规模图查询 ⭐⭐⭐⭐
Neo4j 血缘关系网络、影响分析、溯源分析 大量结构化属性存储、高频更新 ⭐⭐⭐⭐⭐
Hive Metastore Hive/Spark 生态、表结构自动采集 业务元数据、图查询、跨平台血缘 ⭐⭐⭐

2.3 一张图看懂元数据分类与存储选型

下面这张图是我自己总结的元数据分类与存储选型框架。你可以把它当作一个决策参考。

元数据分类与存储选型框架 元数据 技术元数据 业务元数据 表结构信息 ETL作业信息 数据质量 业务定义 数据所有者 使用场景 MySQL / Hive Metastore Neo4j + MySQL 混合 选型建议 • 技术元数据(结构化)→ MySQL 或 Hive Metastore,适合批量查询和事务管理 • 业务元数据 + 血缘关系 → Neo4j 图数据库,适合多跳溯源和影响分析 • 推荐混合架构:MySQL 存属性,Neo4j 存关系,通过 ID 关联

2.4 我的选型建议

说了这么多,到底该怎么选?我个人的经验是:不要只用一种存储。

我目前在做的特征平台,采用的是混合存储架构:

  • MySQL:存储表结构、字段定义、作业配置等结构化元数据。每天定时同步到 Neo4j。
  • Neo4j:存储字段级血缘关系、作业依赖关系、上下游影响链路。用于实时血缘查询。
  • Hive Metastore:作为 Hive/Spark 表的元数据源,通过定时任务同步到 MySQL 和 Neo4j。

这种架构的好处是:各取所长,互不干扰。MySQL 负责事务和批量查询,Neo4j 负责图遍历和关系分析,Hive Metastore 负责与大数据生态对接。

一个小技巧:如果你刚开始做血缘追踪,可以先从 MySQL + Hive Metastore 起步。等血缘关系复杂到 MySQL 撑不住时,再引入 Neo4j。不要一开始就上全套,容易把自己搞死。

好了,元数据的基础就聊到这里。记住一句话:元数据是血缘追踪的命根子。分类清楚、存储选型合理,后面的血缘解析和可视化才能顺风顺水。