1、指标层设计概述:什么是指标层、指标层在数据仓库中的位置、为什么需要指标层

大家好,我是这次课程的主讲。咱们直接进入正题。

指标层,英文叫 Metrics Layer。很多朋友第一次听到这个词,会觉得它是个新概念。其实不然。指标层不是什么高大上的新架构,它更像是一个「翻译层」——把底层那些乱七八糟的物理表、字段名,翻译成业务人员能看懂、能直接用的指标。

什么是指标层?

说白了,指标层就是一组经过统一口径定义、标准化计算逻辑的指标集合。它位于数据仓库的模型层之上,应用层之下。

我个人的理解是:指标层是数据仓库的「语义层」。它不存原始数据,只存「如何计算这个指标」的规则。

核心定义:指标层 = 业务指标 + 计算逻辑 + 口径管理。它让「销售额」这个说法,在全公司只有一个计算方式。

举个例子。你公司有 CRM 系统、ERP 系统、还有一堆 Excel 报表。每个系统里都有「客户数」这个字段。但 CRM 的客户数是「注册用户」,ERP 的客户数是「有交易记录的用户」。口径不一样,数据对不上。指标层就是来解决这个问题的——它把「客户数」统一成「过去 30 天有过至少一笔交易的客户去重数」,然后所有报表都从这个层取数。

指标层在数据仓库中的位置

咱们先看一张图,你就明白了。

指标层在数据仓库中的位置 数据仓库分层架构 — 指标层位置 ODS 层(操作数据存储) DWD 层(明细数据层) DWS 层(汇总数据层) 📊 指标层(Metrics Layer) 统一口径 · 标准化计算 · 业务语义 应用层(报表 / 看板 / API) 各层职责 ODS:原始数据 DWD:清洗明细 DWS:轻度汇总 指标层:语义定义 应用层:消费展示

从这张图可以清楚看到:指标层在 DWS 之上、应用层之下。它不直接对接原始数据,而是基于已经清洗、汇总好的数据,做二次语义封装。

我记得有一次给一家电商公司做数据治理。他们的 BI 团队直接对着 DWD 层写 SQL,每个报表里都有一段长达 200 行的「销售额」计算逻辑。结果呢?三个报表算出三个不同的销售额。后来我把指标层架上去,所有报表统一调用指标层接口,问题就解决了。

为什么需要指标层?

这个问题,我分三点来讲。

1. 解决口径不一致的问题

这是最直接的原因。没有指标层,每个分析师、每个报表都在自己定义指标。同一个「活跃用户」,有人算「登录过就算」,有人算「有过操作行为才算」。口径打架,数据没法用。

我的经验:口径不一致是数据团队的「慢性病」。初期不痛不痒,等公司做到一定规模,你会发现所有跨部门的数据对账都在吵架。指标层就是那个「裁判」。

2. 提升开发效率

你想想看,如果没有指标层,每次新报表需求来了,开发都得重新写一遍指标计算逻辑。重复劳动,还容易出错。

有了指标层,指标的定义和计算逻辑只写一次。后续所有应用层直接引用。改口径也只需要改指标层一处,不用满世界找 SQL。

3. 让业务人员能自助取数

这个点很关键。很多公司花大价钱上了数据平台,但业务人员还是得找 IT 要数据。为什么?因为底层表名是 t_ord_20231023_di,字段名是 amt,业务看不懂。

指标层把这些翻译成「订单金额」、「客户数」、「客单价」。业务人员通过指标层,自己就能拖拽出报表。这才是数据驱动业务的真正落地。

注意:指标层不是银弹。它解决的是「语义统一」和「计算复用」的问题,解决不了「数据质量差」和「源系统数据不准」的问题。底层数据是垃圾,指标层再漂亮也是垃圾。

指标层的核心组成

我习惯把指标层拆成三个部分:

组成部分 说明 举例
原子指标 不可再拆分的业务度量 订单金额、用户数、访问次数
派生指标 基于原子指标计算得到 客单价 = 订单金额 / 用户数
维度 指标的观察角度 时间、地区、产品品类

举个例子。原子指标「订单金额」加上维度「时间」和「地区」,就变成了「2024年华东区订单金额」。如果再除以「用户数」,就得到「2024年华东区客单价」——这就是一个派生指标。

一个简单的指标层定义示例

下面我用伪代码展示一下指标层的定义方式。实际项目中可能会用 YAML、JSON 或者专门的指标管理平台来定义。

# 指标层定义示例(YAML 格式)
metrics:
  - name: order_amount
    display_name: "订单金额"
    description: "用户下单支付的总金额,含税"
    type: atomic
    data_source: dws.dws_order_daily
    field: total_amount
    aggregation: sum
    filters:
      - status = 'paid'
  
  - name: order_count
    display_name: "订单数"
    description: "支付成功的订单数量"
    type: atomic
    data_source: dws.dws_order_daily
    field: order_id
    aggregation: count_distinct
    filters:
      - status = 'paid'
  
  - name: avg_order_value
    display_name: "客单价"
    description: "平均每笔订单的金额"
    type: derived
    formula: "order_amount / order_count"
    depends_on:
      - order_amount
      - order_count

你看,这样定义之后,任何报表工具只要接入指标层,就能直接使用「客单价」这个指标,不用关心它背后的计算逻辑。

避坑指南

我曾经踩过一个坑:指标层定义得太细。把「上午的订单金额」和「下午的订单金额」都定义成独立指标。结果指标数量膨胀到上千个,维护成本极高。

后来我总结了一个原则:指标层只定义业务语义,不定义业务场景。场景(比如「上午 vs 下午」)应该由应用层通过维度筛选来实现,而不是在指标层硬编码。

核心原则:指标层做「定义」,不做「枚举」。一个指标 + 多个维度 = 无限场景。别把场景写死在指标里。