3. 元数据模型设计:指标分类、指标属性定义、维度与度量建模、血缘关系设计

好,咱们进入第三章节。说实话,元数据模型设计是整个指标字典的「骨架」。骨架没搭好,后面填再多肉也站不起来。我在好几个项目里都见过这种情况——指标字典建了半年,结果分类乱成一锅粥,属性定义各说各话,最后谁也查不清哪个指标是谁算的。

这一章,咱们就把骨架搭结实。我会从四个核心部分展开:指标怎么分类、属性怎么定义、维度和度量怎么建模、血缘关系怎么设计。嗯,咱们一个一个来。

3.1 指标分类:别让指标「无家可归」

指标分类,说白了就是给每个指标找个「家」。你想想看,几百个指标堆在一起,没有分类,找起来得多痛苦?

我个人习惯用三层分类体系:

  • 业务域:最顶层,按业务板块划分。比如「交易域」、「用户域」、「营销域」。
  • 业务过程:中间层,按具体业务流程划分。比如「交易域」下面可以分「下单」、「支付」、「退款」。
  • 指标主题:最底层,按分析主题划分。比如「下单」下面可以分「订单量」、「订单金额」、「客单价」。

关键原则:每个指标只能属于一个叶子节点。不能一个指标既属于「订单量」又属于「支付量」,那分类就失去意义了。

我在项目中遇到过一种情况:业务方把「活跃用户数」同时挂在「用户域」和「增长域」下面。结果两个团队算出来的数字不一样,扯皮扯了半个月。后来我们强制规定——每个指标只能挂在一个分类节点下,如果有跨域需求,用「标签」来解决。

3.2 指标属性定义:把「身份证」办齐

指标属性,就是指标的「身份证信息」。属性定义得越全,后面用起来越顺手。

我建议把属性分成三组:

属性分组 属性名称 说明 示例
基础属性 指标名称 业务可读的名称 当日订单支付金额
指标编码 全局唯一标识 IND_TRX_PAY_AMT_D
指标定义 业务含义描述 用户当日成功支付的订单总金额
所属分类 指向分类树叶子节点 交易域 > 支付 > 支付金额
技术属性 数据类型 存储格式 DECIMAL(18,2)
计算口径 SQL 或公式描述 SUM(pay_amt) WHERE status='SUCCESS'
更新频率 数据刷新周期 T+1 / 实时
管理属性 负责人 指标 Owner 张三
安全等级 数据敏感度 L1 / L2 / L3

一个小技巧:指标编码最好带点「语义」。比如 IND_TRX_PAY_AMT_D,IND 代表指标,TRX 代表交易域,PAY 代表支付过程,AMT 代表金额,D 代表日粒度。这样看编码就能猜出七八分含义。

3.3 维度与度量建模:分清「看什么」和「算什么」

维度是「看什么」,度量是「算什么」。这个区分搞不清楚,指标字典就容易变成一锅粥。

举个例子:「按城市统计的订单金额」——「城市」是维度,「订单金额」是度量。

我习惯用下面的模型来设计:

指标 = 度量 + 维度约束 + 时间范围 + 聚合方式

具体来说:

  • 度量:原子指标,不可再拆。比如「支付金额」、「订单数量」。
  • 维度:分析的角度。比如「时间」、「城市」、「渠道」、「用户等级」。
  • 维度约束:对维度值的过滤。比如「城市 = '北京'」。
  • 时间范围:数据的时间窗口。比如「2024-01-01 到 2024-01-31」。
  • 聚合方式:SUM、COUNT、AVG、MAX、MIN 等。

注意:同一个度量搭配不同的维度,会产生不同的指标。比如「支付金额」按「城市」聚合是「城市支付金额」,按「渠道」聚合是「渠道支付金额」。这两个指标虽然底层数据一样,但业务含义不同,必须分别定义。

我曾经见过一个团队,把「支付金额」定义成一个指标,然后说「维度可以随便组合」。结果业务方问「北京渠道的支付金额是多少」,数据团队算了三个版本,每个都不一样。为什么?因为维度组合的过滤条件没定义清楚。

3.4 血缘关系设计:让数据「有迹可循」

血缘关系,就是指标从哪来、到哪去、中间经过了哪些变换。没有血缘关系,指标出了问题你根本不知道是源头脏了还是中间算错了。

我建议至少记录三层血缘:

  1. 源系统 → 贴源层:数据从哪个业务系统来,对应哪张表、哪个字段。
  2. 贴源层 → 明细层:经过哪些清洗、转换、关联。
  3. 明细层 → 指标层:经过哪些聚合计算,生成最终指标。

下面这张图展示了完整的血缘链路:

指标血缘关系链路 源系统 A 源系统 B 源系统 C 贴源层(ODS) ETL 清洗、转换 明细层(DWD) 聚合计算 指标层(DWS / ADS) 每个箭头都对应一条血缘记录:源表 → 目标表 → 转换逻辑 → 字段映射。记录越细,排查问题越快。

在实际落地时,我建议用一张血缘关系表来存储:

CREATE TABLE meta_lineage (
  lineage_id      BIGINT PRIMARY KEY,
  source_table    VARCHAR(100),   -- 源表名
  source_field    VARCHAR(100),   -- 源字段
  target_table    VARCHAR(100),   -- 目标表名
  target_field    VARCHAR(100),   -- 目标字段
  transform_logic TEXT,           -- 转换逻辑描述
  etl_job_id      VARCHAR(50),    -- 对应 ETL 任务
  create_time     DATETIME
);

避坑指南:血缘关系一定要「自动采集」,不要手工维护。我曾经见过一个团队,靠 Excel 手工记录血缘,三个月后 Excel 丢了,整个指标字典的血缘全断了。后来我们接入了数据治理平台,自动解析 SQL 中的表字段依赖,血缘才真正「活」起来。

3.5 元数据模型总览

最后,我把这四个部分串起来,形成一个完整的元数据模型。你可以在实际项目中直接参考:

元数据模型 = {
  "指标分类树": {
    "业务域": ["交易域", "用户域", "营销域", ...],
    "业务过程": ["下单", "支付", "退款", ...],
    "指标主题": ["订单量", "支付金额", "退款率", ...]
  },
  "指标属性": {
    "基础属性": ["名称", "编码", "定义", "分类"],
    "技术属性": ["数据类型", "计算口径", "更新频率"],
    "管理属性": ["负责人", "安全等级", "创建时间"]
  },
  "维度与度量": {
    "度量": ["支付金额", "订单数量", "用户数"],
    "维度": ["时间", "城市", "渠道", "用户等级"],
    "聚合方式": ["SUM", "COUNT", "AVG", "MAX", "MIN"]
  },
  "血缘关系": {
    "源系统 → 贴源层": "字段级映射",
    "贴源层 → 明细层": "清洗转换逻辑",
    "明细层 → 指标层": "聚合计算逻辑"
  }
}