简介:《数据中台实战:手把手教你搭建数据中台》电子书,面向推进数据化转型的企业高层、产品经理、运营/设计与开发人员,以及对数据领域感兴趣的学生与从业者。全书以数据采集、存储与计算、数据打通、数据应用四条主线,拆解从零到一搭建数据中台的完整路径,涵盖埋点采集用户行为数据、指标体系管理与ODS至ADS分层建模、标签平台与用户圈选、人货场分析、自助分析平台、自动化营销等模块,并强调先判断自身业务密度与复杂度是否真的需要中台,避免生搬硬套。压缩包内共1个文件,为PDF格式电子书,约11.3MB,目录与章节结构完整,可按顺序逐章研读或定位查阅。目前已有402人学习下载,适合作为中台产品经理入门、团队方案讨论与项目落地的案头参考。
1. 需求先立住:三条以上产品线才值得谈数据中台
遇到「数据中台搭建」这类需求文档,我一般先不急着画架构图,而是先问一句:你们有几条产品线,同名指标是不是已经打过三次架。数据中台的价值不在于技术栈有多新,而在于它把分散在各条产品线里的采集、存储、打通、应用四件事收拢成一套公共能力,让大数据不再是一个个孤岛。如果只有一条主业务线,业务密度撑不起复用,硬上中台往往只是给报表加了一层转手,开发反而更慢。这份方案适合三类读者:要交完整设计或毕设的学生、要给公司出一版可交付方案的从业者、以及准备往中台产品方向走的人。下面按「需求判断—总体架构—采集与建模—打通与应用—避坑—验收」的顺序,把从 0 到 1 的路径拆开讲,每一章都落到能照抄的结构和参数上。
2. 总体架构设计:采集、计算、服务、应用四层与双中台边界
2.1 四层架构与每层要交出的东西
数据中台不是一台机器,而是一条从数据产生到数据消费的流水线。往下看四层:数据采集层负责把业务库、日志、埋点三路数据收进来;数据计算层负责清洗、分层建模、指标计算;数据服务层把算好的结果封装成接口和数据集;数据应用层才是运营、产品、管理层真正看到的东西。分层的目的不是好看,而是变更隔离——埋点字段改了不影响指标层,指标口径改了不用动采集任务,权限也能按层收口。
| 层级 | 核心职责 | 常见技术选型 | 交付物 |
|---|---|---|---|
| 数据采集层 | 业务库同步、日志抽取、埋点上报 | CDC 工具、日志采集组件、消息队列 | 贴源表、原始日志、事件流 |
| 数据计算层 | 清洗去重、分层建模、指标计算 | 离线计算引擎、实时计算引擎 | ODS/DWD/DWS/ADS 各层表 |
| 数据服务层 | 接口封装、数据集市、权限控制 | 查询引擎、接口服务 | 指标接口、人群包、标签查询 |
| 数据应用层 | 看板、自助分析、营销、推荐 | 可视化平台、营销系统 | 报表、看板、活动效果报告 |
工程目录按层分库,一层一个库名,禁止跨层引用,这是后面排查问题时能快速定位的前提:
# 数仓工程目录:层级即库名,后缀标注更新方式 warehouse/ ├── ods/ # 贴源层:与源表结构基本一致,只做类型统一 │ ├── ods_order_di/ # di = 日增量,df = 日全量 │ └── ods_user_df/ ├── dwd/ # 明细层:清洗、去重、维度关联,保留最细粒度 │ └── dwd_trade_order_detail_di/ ├── dws/ # 汇总层:按主题和粒度轻度聚合,供多处复用 │ └── dws_user_action_1d/ ├── ads/ # 应用层:直接对接看板与接口,一表服务一组指标 │ └── ads_trade_dashboard_1d/ └── dim/ # 公共维度:日期、商品、渠道、地区命名规范建议统一成「层级_主题_粒度_更新周期」,比如dws_user_action_1d表示汇总层、用户行为主题、按天粒度。这套命名看着啰嗦,但半年后接手的人能只凭表名判断能不能用、要不要重跑,省掉大量翻文档的时间。
2.2 业务中台与数据中台:谁产数据,谁消费数据
两个中台经常被混着讲,实际分工很清楚:业务中台把用户、商品、交易、支付、营销这些通用能力做成可插拔的中心,让各条产品线不再重复造登录、下单、发券;数据中台把这些中心和各产品线沉淀下来的数据收上来,做成指标、标签、人群包,再反哺业务。一句话概括——业务中台让业务数据化,数据中台让数据业务化。
| 关注点 | 业务中台 | 数据中台 |
|---|---|---|
| 建设目标 | 通用业务能力复用 | 数据资产化与数据反哺 |
| 核心资产 | 用户、商品、交易、支付、营销五个中心 | 指标字典、标签宽表、人群包、数据接口 |
| 服务对象 | 各产品线研发团队 | 运营、产品、管理层、商家、终端用户 |
| 交付形态 | 可插拔的业务模块 | 接口、看板、人群包、推荐结果 |
| 前置依赖 | 跨部门业务梳理 | 业务中台或各产品线数据源 |
这条边界直接决定建设成本。有业务中台的团队,用户标识、商品编码、订单状态已经统一,数据中台只管对接和建模;没有业务中台的团队,得先逐条产品线做数据调研,把「同一个用户在两个系统里是不是同一个人」这种问题先解决掉。通常的做法是:先按业务中台的思路把用户中心和商品中心的最小集做出来,再启动数据中台的采集,不然采集上来的数据连主键都对不齐。
2.3 十种角色与一份能落地的排期
中台是跨部门工程,人员配不齐,后面每一步都会卡在「这个字段谁负责」。一个能跑起来的数据中台项目通常需要十种角色:中台负责人、数据产品经理、数据分析师、数据开发工程师、算法工程师、可视化前端、测试、运维、业务方对接人、项目 PM。其中业务方对接人最容易被忽略,但埋点验收、指标口径确认、看板试用全靠他推。
| 阶段 | 周期参考 | 关键动作 | 里程碑 |
|---|---|---|---|
| 需求与调研 | 2~3 周 | 盘点产品线、梳理指标、定口径归属 | 指标清单与数据源清单 |
| 架构与规范 | 1~2 周 | 分层设计、命名规范、权限模型 | 数仓规范文档 |
| 采集接入 | 3~4 周 | 埋点上线、业务库同步、日志抽取 | 贴源层全量可用 |
| 建模与指标 | 4~6 周 | ODS 到 ADS 全链路、指标字典上线 | 核心指标可查 |
| 打通与应用 | 4~6 周 | 标签宽表、看板、营销活动接入 | 首批看板上线 |
| 验收与迭代 | 持续 | 数据质量监控、口径变更流程 | 验收报告 |
排期表里最该留 buffer 的是采集接入,埋点从需求评审到客户端发版通常要跨一个版本周期,很多项目不是卡在建模,而是卡在「埋点还没全量」。
提示:中台负责人这一层不能省。它不写代码,但负责在指标口径打架、跨部门资源协调时拍板,缺了这一层,项目会在第三周开始无限期扯皮。
3. 采集与存储:埋点事件模型、分层建模与指标口径
3.1 埋点方案:事件、属性和一张谁都能查的管理表
埋点最容易翻车的地方不是技术,而是命名。同一个「加入购物车」动作,A 产品线叫add_cart,B 产品线叫cart_add,半年后做跨产品线分析就得写两套逻辑。规范的做法是先定事件模型:一个事件由事件名、用户标识、时间、页面上下文、业务属性五部分组成,公共属性(设备、渠道、版本、网络)由 SDK 统一带上,业务属性按事件单独定义,不许往公共属性里塞业务字段。
// 埋点上报结构:event_id 用于服务端幂等去重,避免网络重试造成重复计数 { "event_id": "evt_20240610_9f3a2c", // 客户端生成,全局唯一 "event_name": "add_cart", // 事件名,下划线命名,全公司唯一 "user_id": "u_10086", // 登录用户标识,未登录时为空 "device_id": "d_7a8f", // 设备标识,用于登录前的行为归因 "event_time": "2024-06-10 10:21:33", // 客户端时间,服务端再补一个接收时间 "page": { "page_id": "pdp_001", // 页面唯一编码,不是页面路径 "page_name": "商品详情页", "referrer_page_id": "home_001" // 来源页面,用于漏斗分析 }, "props": { "sku_id": "s_2231", "category_id": "c_dress", "price": 299.00, "quantity": 1 } }event_id这个字段值得单独说:移动端网络抖动时 SDK 会重试上报,没有幂等键,服务端就会把一次加购记成两次,最后看板上的转化率全是玄学。上报结构定好后,配套建一张埋点管理表,字段包括事件名、中文名、触发时机、属性列表、负责人、上线版本、状态。这张表是后续验收和交接的依据,新需求评审时先查表,重名就复用,不许新建。
3.2 业务库同步与日志抽取:把失败暴露出来
采集一般走两条路:业务库用 CDC 做增量同步,每天再跑一次全量对齐做兜底;日志和埋点落到消息队列后按小时或按天抽取进数仓。同步任务配置里有几个参数必须显式写死,不能靠默认值:
# 一个业务库同步任务的配置要点(以订单表为例) task: name: sync_ods_order_di source: type: mysql table: t_order split_pk: order_id # 切分主键,大表并行读取靠它 where: "update_time >= '${bizdate} 00:00:00'" sink: type: hive table: ods_order_di partition: dt='${bizdate}' # 分区字段统一为 dt,重跑只覆盖当天 write_mode: overwrite # 覆盖写,保证重跑幂等 control: parallelism: 4 # 并发数,按源库压力调,别一上来就拉满 dirty_record_limit: 100 # 脏数据阈值,超过就失败而不是静默丢弃 retry: 3 alert: on_failure # 失败必须告警到人,不能只写日志三个参数解释一下:write_mode用覆盖写而不是追加写,是为了让任务可以安全重跑,跑十遍结果一致;dirty_record_limit是黑匣子的开关,脏数据超过阈值就让任务失败,而不是把坏数据灌进下游;alert必须接到人,很多团队报表数字不对,根因就是同步任务半夜失败、下游空跑、看板显示零,第二天没人发现。
3.3 分层建模:从 ODS 到 DWD/DWS/ADS 的 SQL 落地
分层建模的价值在于每一层只解决一类问题。ODS 贴源,不做业务加工;DWD 做清洗、去重、维度关联,保留最细粒度;DWS 按主题聚合,供多个应用复用;ADS 直接面向看板和接口,一表服务一组指标。
-- DWD 明细层:订单明细宽表,一天一个分区,重跑先覆盖分区保证幂等 INSERT OVERWRITE TABLE dwd_trade_order_detail_di PARTITION (dt = '${bizdate}') SELECT o.order_id, o.user_id, o.sku_id, o.pay_amount, o.order_status, o.create_time, p.category_id, -- 关联商品维表补齐类目 p.first_category_id, c.channel_name -- 关联渠道维表,供流量归因使用 FROM ods_order_di o LEFT JOIN dim_product_df p ON o.sku_id = p.sku_id AND p.dt = '${bizdate}' LEFT JOIN dim_channel_df c ON o.channel_id = c.channel_id AND c.dt = '${bizdate}' WHERE o.dt = '${bizdate}' AND o.is_deleted = 0 -- 过滤逻辑删除 AND o.order_id IS NOT NULL; -- 主键为空直接丢弃并计入质量报告-- DWS 汇总层:按用户+日期聚合行为,标签平台和留存分析都从这里取数 INSERT OVERWRITE TABLE dws_user_action_1d PARTITION (dt = '${bizdate}') SELECT user_id, COUNT(IF(event_name = 'page_view', 1, NULL)) AS pv, COUNT(DISTINCT IF(event_name = 'page_view', page_id, NULL)) AS view_page_cnt, SUM(IF(event_name = 'add_cart', 1, 0)) AS add_cart_cnt, SUM(IF(event_name = 'pay_success', pay_amount, 0)) AS pay_amt FROM dwd_user_event_di WHERE dt = '${bizdate}' GROUP BY user_id;-- ADS 应用层:交易看板日粒度表,一天一行,看板直接查这张表,不再扫明细 INSERT OVERWRITE TABLE ads_trade_dashboard_1d PARTITION (dt = '${bizdate}') SELECT '${bizdate}' AS dt, COUNT(DISTINCT order_id) AS order_cnt, SUM(pay_amount) AS gmv, COUNT(DISTINCT user_id) AS pay_user_cnt, SUM(IF(order_status = 'refunded', pay_amount, 0)) AS refund_amt FROM dwd_trade_order_detail_di WHERE dt = '${bizdate}';三段 SQL 串起来就是一条最小可用链路。注意 DWS 和 ADS 都不要回读 ODS,跨层引用一旦开了口子,后面就没法判断一张表的上游到底是谁,排查问题只能靠猜。另外每个任务都要配一个质量校验,最简单的就是行数同比波动检查,波动超过阈值先挂起下游。
3.4 指标字典:把口径写死在表里
比建模更容易出问题的是口径。「活跃用户」到底是打开过 App 还是有过任何行为,「GMV」含不含退款、含不含未支付订单,三个部门能给出三个答案。解决办法不是开会,而是建一张指标字典表,把业务口径和技术口径分开写清楚,变更必须留版本。
CREATE TABLE IF NOT EXISTS meta_indicator_dict ( indicator_code STRING COMMENT '指标英文编码,全公司唯一', indicator_name STRING COMMENT '指标中文名,看板展示名', biz_definition STRING COMMENT '业务口径:谁在什么场景下怎么算', tech_definition STRING COMMENT '技术口径:来源表、过滤条件、聚合方式', stat_period STRING COMMENT '统计周期:日/周/月/实时', owner STRING COMMENT '口径负责人,改口径必须经他确认', version STRING COMMENT '口径版本号,每次变更递增并留变更说明', update_time STRING COMMENT '最近更新时间' ) COMMENT '指标字典:口径的唯一事实来源'; -- 示例:一个指标的完整定义 INSERT INTO meta_indicator_dict VALUES ( 'gmv', '成交总额', '统计周期内支付成功订单的商品金额之和,不含运费,退款单独列为退款金额不冲减', 'dwd_trade_order_detail_di 按 dt 分区,过滤 order_status in (paid, shipped, finished),sum(pay_amount)', '日', '数据产品经理', 'v1.2', '2024-06-10' );技术口径这一栏要写到「表 + 过滤条件 + 聚合方式」的粒度,不能只写一句「按订单表统计」。新人接手时,照着这一栏就能复现出一模一样的数字,这才叫口径受控。
4. 数据打通与应用:标签宽表、人货场看板与自动化营销
4.1 标签平台:用一张宽表打通行为数据和业务数据
数据打通要解决两件事:一是把同一个用户的行为数据和交易数据对上,二是把不同产品线的同一个用户认出来。落地形态通常是标签宽表——一行一个用户,列是各类标签,查询时不用多表关联,圈选速度才有保障。
-- 用户标签宽表:宽表换查询速度,标签列按需扩展 CREATE TABLE IF NOT EXISTS dws_user_tag_wide_df ( user_id STRING COMMENT '跨产品线统一后的用户标识', last_active_days INT COMMENT '距今天数,统计类标签', pay_amt_30d DECIMAL(18,2) COMMENT '近30天支付金额', order_cnt_90d INT COMMENT '近90天下单次数', prefer_category STRING COMMENT '偏好一级类目,规则类标签', price_band STRING COMMENT '价格带:low/mid/high', life_stage STRING COMMENT '生命周期:新客/活跃/沉睡/流失', value_level STRING COMMENT '价值分层:高/中/低', dt STRING COMMENT '标签快照日期,分区字段' ) COMMENT '用户标签宽表:一行一个用户' PARTITIONED BY (dt STRING);标签的生成走「定义—计算—校验—上线」四步,定义写进标签字典,计算用调度任务每天跑一次,校验看空值率和分布漂移。宽表每天存一份全量快照,方便回溯「这个用户上周是什么标签」,但代价是存储涨得快,通常只保留最近 90 天分区,更早的归档。
圈选是标签平台最常用的功能,本质就是一段带条件的 SQL,条件由运营在界面上勾选后拼接生成:
-- 人群圈选:近30天有支付、偏好连衣裙、价格带中高,取交集后落人群包 INSERT OVERWRITE TABLE ads_crowd_pack_20240610 PARTITION (dt = '${bizdate}') SELECT user_id FROM dws_user_tag_wide_df WHERE dt = '${bizdate}' AND pay_amt_30d > 0 AND prefer_category = 'dress' AND price_band IN ('mid', 'high');人群包表要带有效期和使用记录,谁在什么时间圈了多少人、投放到哪个渠道,都要能查。否则运营一个月圈两百个包,最后没人知道哪个包真正起过作用。
4.2 人货场四类分析:给不同角色看不同粒度
数据应用最容易犯的错是给所有人看同一张表。管理层的诉求是大盘趋势和同比环比,运营的诉求是明细和归因,商家只能看自己店铺的数据。按用户、商品、流量、交易四个主题拆开设计,每个主题下面挂核心指标和常用维度:
| 分析主题 | 核心指标 | 常用维度 | 主要使用角色 |
|---|---|---|---|
| 用户分析 | 新增、活跃、留存、复购、生命周期分布 | 渠道、版本、价格带、类目偏好 | 运营、产品 |
| 商品分析 | 曝光、点击、加购、支付转化、库存周转 | 类目、价格带、供应商、上新周期 | 商品运营、供应链 |
| 流量分析 | PV、UV、停留时长、跳失、来源构成 | 页面、渠道、活动、设备 | 运营、市场 |
| 交易分析 | GMV、订单量、客单价、退款率、支付转化 | 时间、渠道、类目、地区 | 管理层、财务 |
交易看板做成一层大盘 + 一层下钻,大盘给领导看四个数:GMV、订单量、支付用户数、退款金额,一屏之内不放第二个屏的东西;下钻给运营,能点进某个渠道看它当天的转化漏斗。经验是管理层看板指标超过八个,基本就没人看了。
4.3 自助分析、自动化营销与推荐的接入方式
自助分析平台解决的是「每个看板都提需求、数据团队排期排到三个月后」的问题。做法是把指标和维度做成可配置项,业务人员自己拖拽生成看板,数据团队只维护指标层和权限模型。这要求指标字典足够干净,一个指标一个口径,否则自助出来的看板互相打架。千人千面的看板通过「用户—看板—权限」三张表控制,谁看到哪些指标、能不能导出,都在配置里定死。
自动化营销把「圈人、触达、发券、复盘」串成一条流水线,业务只配策略,执行交给系统:
# 一次周期性召回活动:策略与执行分离,业务在后台改参数即可 campaign: name: "沉睡用户召回_30天" crowd: "ads_crowd_pack_20240610" # 人群包,由圈选任务产出 channel: ["sms", "push"] # 多渠道,按优先级降级 schedule: start: "2024-06-11" cron: "0 10 * * *" # 每天10点执行一次 frequency_cap: per_user_per_week: 2 # 频控,防止打扰导致卸载 content: template_id: "T_SLEEP_RECALL_01" coupon_id: "C_20_OFF_100" # 关联优惠券,发放走营销中心 effect: callback_table: "ads_campaign_effect_1d" # 效果回流表,活动结束自动出报告频控、幂等、效果回流这三个配置缺一不可:没有频控,用户一周收七条短信;没有幂等,任务重跑会重复发券;没有效果回流,活动做完不知道转化率是多少。推荐系统则通常分两套:离线推荐用标签宽表和物品特征做召回排序,每天算一次;实时推荐接行为流,在会话内调整结果。毕设或课设场景下,先把离线链路跑通,再做实时,比一上来搭两套清晰得多。
5. 避坑与排查:五个最容易翻车的环节
5.1 口径打架:同一个指标三个数
现象是周会上运营、财务、数据团队各报一个 GMV,差几十万。原因几乎都出在统计对象不一致:有人算支付成功,有人算下单,有人把退款冲减了,还有人只算主站不算渠道。解决靠制度和工具两条腿:制度上每个指标指定唯一 owner,口径变更走版本;工具上所有看板只允许从指标字典对应的 ADS 表取数,禁止各自写 SQL 查明细。发现口径不一致时,先对数,从 ADS 反查到 DWD 再反查到 ODS,看差异出在哪一层,而不是先改代码。
5.2 埋点漏报与重复上报
现象是加购数比订单数还低,或者同一个用户的点击量高得离谱。原因通常有三个:页面切换时 SDK 重复初始化导致重复上报;网络重试没有幂等键;埋点上线时只测了主流程,弱网和返回键场景没覆盖。解决方式是把event_id做服务端去重,按event_id建唯一约束;埋点验收必须用测试账号跑完整路径,包括杀进程重进、断网重连;上线后连续三天盯核心事件的量级曲线,异常波动当天定位。
-- 埋点质量体检:同一天按事件名看去重前后的量差,差得多说明重复上报严重 SELECT dt, event_name, COUNT(1) AS raw_cnt, COUNT(DISTINCT event_id) AS dedup_cnt, COUNT(1) - COUNT(DISTINCT event_id) AS dup_cnt FROM ods_user_event_di WHERE dt = '${bizdate}' GROUP BY dt, event_name ORDER BY dup_cnt DESC LIMIT 20;5.3 同步任务悄悄失败,报表还在跑
现象是看板打开正常,数字一整天没变。原因多半是同步任务失败后,下游调度没有配置依赖,ADS 任务照样跑,但读到的是空分区或旧分区,最后按零处理。解决要三道闸:任务失败立刻告警到人;下游任务强依赖上游分区就绪;每个 ADS 表加行数波动校验,同比下跌超过 30% 自动挂起并通知。这道校验写起来就是一段 SQL,但能省掉半夜被电话叫起来对数的时间。
5.4 标签宽表膨胀,圈选从三秒变三分钟
现象是标签越加越多,宽表列数上百,圈选一次要等几分钟。原因是每天存全量快照、历史分区不清理、常用标签没有做预聚合。解决:分区只保留最近 90 天,更早的转归档表;高频圈选条件做成组合标签提前算好;人数特别大的场景改用位图结构做交并差。标签数量不是越多越好,运营真正高频使用的通常不超过三十个,剩下的先下线,需要时再加回来。
5.5 看板上线没人用,或者商家看到了全站数据
前者是需求没立住,后者是权限没做行级隔离。看板没人用的典型特征是上线首月访问量个位数,原因通常是做之前没定「谁每天要用它做什么决策」。解决方式很简单:每个看板上线前必须绑定一个使用人和一个使用场景,找不到就说明不该做。权限问题更危险,商家账号能查到全站 GMV 属于数据事故,做法是在 ADS 层就带上商家标识,接口按登录身份自动拼接待过滤条件,不依赖前端隐藏。
注意:行级权限一定要做在数据服务层,做在前端只是障眼法,抓包就能绕过。
6. 验收与答辩:把「建成了」证明给评审看
验收最忌讳拿着一份功能清单说「都做完了」。评审真正想看的是数据能不能从头走到尾,所以我会准备一张按层拆开的验收表,每一项都要能拿出证据:
| 验收层 | 验收项 | 通过标准 | 留痕证据 |
|---|---|---|---|
| 采集 | 核心事件覆盖率 | 核心事件覆盖 ≥95%,重复上报率 <1% | 埋点验收报告 |
| 存储 | 分区完整性与行数波动 | 近 30 天分区无缺失,波动在阈值内 | 质量校验任务截图 |
| 建模 | 指标可复现 | 同一指标两人独立计算,结果一致 | 指标字典 + 对数记录 |
| 打通 | 标签覆盖率与圈选耗时 | 可识别用户标签覆盖率 ≥80%,圈选 <10 秒 | 标签平台日志 |
| 应用 | 看板使用与权限 | 有明确使用人,越权访问被拦截 | 访问日志 + 权限测试用例 |
答辩演示我一般走一条链路而不是罗列页面:先用测试账号在演示环境产生一条真实行为,等它落进 ODS,再依次打开 DWD、DWS、ADS 三层表,最后回到看板指着那个变化的数字说「这一条数据是从这里来的」。这条链路能走通,说明采集、同步、建模、服务、应用五段都活着;走不通,问题一定出在某一段的依赖没配。再补一个反向演示:把上游任务停掉,让看板报警,证明监控是真的在跑,而不是摆设。
从那以后我每次交付前都强制走一遍这条链路,哪怕只是一个课程设计的小数仓,也会先造一条测试数据从头追到尾。数据项目最怕的不是功能少,而是看起来都对、一追就断。希望这套结构能帮到你,把方案讲成一个能验收的完整闭环。
本文还有配套的精品资源,点击获取