数仓入门篇-数仓分层

0 阅读7分钟

整体架构图解

直接看数仓分层的整体层级图


各层级详解

ODS 层- 操作数据层

  • 定义:数据仓库的“缓冲区”或“贴源层”。它直接同步业务数据库(MySQL, Oracle, Logs 等)的数据,保持与源系统结构基本一致。
  • 核心作用:
    • 隔离风险:避免复杂的清洗逻辑直接影响源系统,也避免源系统变更直接击穿数仓。
    • 历史回溯:源系统通常只保留近期数据或覆盖更新,ODS 层通过全量或增量快照保留历史状态。
    • 数据备份:作为数据的最后一道防线。
  • 设计原则:
    • 结构与源系统一致:字段名、类型尽量保持不变。
    • 不做复杂清洗:仅做简单的非空判断、乱码处理、分区管理。
    • 保留变更痕迹:通常采用 T+1 增量同步、全量快照、Binlog实时同步,现在 T+0 分钟级增量同步也开始流行起来了。
  • 表命名示例:ods_order_info_df (df=daily full, 全量), ods_user_login_di (di=daily increment, 增量)。

实例:
源系统订单表 t_order 有 1000 万条数据。
ODS 层表 ods_t_order_di 每天凌晨同步新增的 10 万条数据,并打上 dt='2026-03-04' 的分区标签。


DIM 层 - 公共维度层

  • 定义:存储一致性维度信息的层级。它是数仓的字典中心,确保全公司对于用户商品城市的定义是统一的。
  • 核心作用:
    • 统一口径:避免不同报表中“北京市”和“北京”被算作两个城市。
    • 维度退化/扁平化:将原本分散在多个系统的维度信息整合成一张宽表(维度建模中的维度表)。
    • 缓慢变化维 (SCD):处理维度属性的历史变化(如用户从“普通会员”变为“VIP”)。
  • 设计原则:
    • 高复用性:所有下游层(DWD/DWS/ADS)都引用这里的维度 ID。
    • 全量存储:维度表通常较小,建议每天全量覆盖或拉链表存储。
  • 表命名示例:dim_user_info_df, dim_product_category_df, dim_date_df

实例:
整合 CRM 系统的用户基本信息 + 积分系统的用户等级 + 埋点系统的用户标签,生成一张唯一的 dim_user_full_df。无论分析销售还是分析点击,都用这张表里的 user_id


DWD 层 - 明细数据层

  • 定义:数仓的核心层。基于 ODS 数据进行清洗、规范化、脱敏、维度关联后生成的明细事实表。
  • 核心作用:
    • 数据清洗:去除脏数据、统一枚举值(如性别统一为 0/1)、空值填充。
    • 维度退化:将常用的维度属性(如商品名称、类目)直接冗余到事实表中,形成大宽表,减少后续查询的 Join 操作。
    • 业务过程建模:按照业务过程(下单、支付、发货、退款)划分主题。
  • 设计原则:
    • 保持明细粒度:一行代表一个具体的业务动作(如一次下单),不进行聚合。
    • 维度模型:通常采用星型模型设计。
  • 表命名示例:dwd_trade_order_detail_di (交易下单明细), dwd_log_page_view_di (页面浏览明细)。

实例:
输入:ODS 的订单表 + ODS 的订单详情表 + DIM 的商品表。
处理:清洗掉测试订单,统一货币单位,将商品名称一级类目冗余进来。
输出:dwd_trade_order_detail_di,包含:order_id, user_id, product_name, category_level1, pay_amount, create_time


DWS 层 - 汇总数据层

  • 定义:基于 DWD 层的明细数据,按主题域和时间粒度进行轻度聚合的层级。
  • 核心作用:
    • 提升性能:预计算常用指标,避免每次查报表都扫描亿级明细数据。
    • 构建指标体系:沉淀原子指标(如 GMV)、派生指标(如近 7 天 GMV)。
    • 服务通用性:为多个不同的应用场景提供统一的中间结果。
  • 设计原则:
    • 按主题建设:如交易主题、流量主题、用户主题。
    • 时间粒度:最常见的是天粒度(日汇总),也有小时粒度或周/月粒度。
    • 维度组合:通常包含 日期 + 核心维度(如用户、商品、地区)。
  • 表命名示例:dws_trade_user_day_sum (用户日交易汇总), dws_item_cate_hour_stat (商品类目小时统计)。

实例:
输入:dwd_trade_order_detail_di (亿级数据)。
处理:按 user_iddt 分组,计算当天的下单次数、总金额、退货金额。
输出:dws_trade_user_day_sum,包含:dt, user_id, order_count_1d, pay_amount_1d
效果:查询某用户一年的数据,只需扫描 365 行,而不是几千万行明细。


ADS 层- 应用数据层

  • 定义:面向具体业务应用的数据层。存放最终的计算结果,直接对接 BI 报表、数据大屏、推荐算法接口或 API 服务。
  • 核心作用:
    • 个性化交付:针对特定需求(如双 11 实时大屏、CEO 日报)定制数据结构。
    • 复杂逻辑终结:包含跨主题域的复杂关联(如:结合交易 DWS + 流量 DWS + 用户 DIM 计算“高价值流失用户”)。
    • 结果导出:数据量通常最小,可直接推送到 MySQL、Redis 或 Elasticsearch 供前端读取。
  • 设计原则:
    • 结果导向:表结构完全匹配前端展示需求(甚至已经是 JSON 格式或透视表结构)。
    • 高时效性:如果是实时大屏,该层可能是秒级/分钟级更新。
  • 表命名示例:ads_ceo_daily_report_df, app_rec_user_list_df, dwa_screen_realtime_gmv

实例:
输入:dws_trade_user_day_sum + dim_user_info
处理:筛选出过去 30 天消费大于 1 万且最近 7 天未登录的用户,提取姓名和手机号。
输出:ads_high_value_churn_user_list,直接供客服系统调用进行电话回访。


全流程案例演示:计算“2026 年 3 月 4 日各省份的销售总额”

老言带你们看一个指标是如何在各层流转的:

  1. Source (业务库):
    • orders 表:{id: 101, user_id: 88, amount: 100, province_code: 'GD', time: '...'}
    • users 表:{id: 88, name: '张三'}
  2. ODS 层:
    • ods_orders_di: 原样同步 orders 表数据,分区 dt='2026-03-04'
    • ods_users_df: 全量同步 users 表。
  3. DIM 层:
    • dim_province: 整理省份代码表 {code: 'GD', name: '广东省'}
    • (此处可能还会生成用户维度宽表,暂略)
  4. DWD 层 (清洗 + 宽表化):
    • dwd_trade_order_detail_di:
      • 关联 ODS 订单 + ODS 用户 + DIM 省份。
      • 清洗:剔除金额为负数的测试单。
      • 退化:将 province_name ('广东省') 直接存入该行。
      • 结果行:{order_id: 101, user_id: 88, amount: 100, province_name: '广东省', dt: '2026-03-04'}
  5. DWS 层 (轻度聚合):
    • dws_trade_province_day_sum:
      • 基于 DWD,按 province_namedt 分组。
      • 计算:sum(amount)
      • 结果行:{dt: '2026-03-04', province_name: '广东省', total_gmv: 5000000} (假设该省当天总共卖了 500 万)。
  6. ADS 层 (应用结果):
    • ads_map_sales_visualization:
      • 为了地图组件展示,格式化数据。
      • 结果:[{name: '广东省', value: 5000000}, {name: '北京市', value: 3000000}, ...]
      • 此表直接推送到 Superset 渲染。

为什么要分层

  1. 清晰的数据血缘:当 ADS 层数据出错时,可以逐层向上排查(ADS->DWS->DWD->ODS),快速定位是计算逻辑错了还是源数据错了。
  2. 避免重复计算:DWS 层沉淀了通用的日/月汇总,如果有 10 个报表都需要“日销售额”,它们都去读DWS,而不是每个人都去扫一遍 DWD 的亿级明细。
  3. 屏蔽底层复杂性:业务分析师只需要关注 DWS 和 ADS 层,不需要理解底层的 3NF 复杂关联或脏数据清洗逻辑。
  4. 灵活应对变化:如果源系统字段变了,只需修改 ODS->DWD 的同步逻辑,DWS 和 ADS 层往往不需要变动(只要核心语义不变)。