订阅更新

同一份订单在三个系统里——主数据采集口径怎么统一?

数据采集手册 第 12 题 约 10 分钟读完

本文目录
  1. 先说结论
  2. 业务场景:三个系统的订单数都不一样
  3. 方案一:定义权威源(Source of Truth)
  4. 方案二:ID Mapping打通
  5. 方案三:One ID + 融合宽表
  6. MDM体系对比
  7. 面试高频追问
  8. 实战踩坑:ID Mapping因CDC延迟漏关联
  9. 总结

先说结论

根因是"主数据未治理":各业务系统独立演进,对同一个业务对象(订单/用户/商品)有不同的字段、口径、状态机。

解决思路三层:① 确定权威源(Master);② 用统一ID映射(ID Mapping);③ 数仓层做"对齐+融合"(One ID)。

没有银弹:MDM是治理工程不是技术问题。数据团队推不动业务方,再好的技术方案也落地不了。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

数据团队最讨厌的事情之一就是"同一个业务对象,从不同系统采过来的数据对不上"。订单可能在交易系统、风控系统、CRM系统里都有,每家定义不一样,数仓接进来就是一锅粥。这道题面试官想看的不是"用一个系统当主",而是你有没有主数据管理(MDM)的体系化思维,能在采集环节把口径统一好。

业务场景:三个系统的订单数都不一样

做日订单大盘时,发现交易系统报50万、风控系统报48万、CRM报52万。三个系统都说自己"对"。仔细排查后发现:交易系统统计的是"创单成功",风控系统统计的是"通过风控"(拒了2万),CRM统计的是"包含线下订单"(多了4万)。每个系统在自己业务域内都对,但放在一起就错了。

三个系统的订单口径差异:
 
  交易系统:
    定义: 用户点击下单按钮成功的订单
    范围: 包含未支付/已支付/已退款
    时间: 用 create_time(下单时间)
 
  风控系统:
    定义: 通过风控的订单(拒单不计)
    范围: 仅含通过风控的部分
    时间: 用 risk_pass_time(风控通过时间)
 
  CRM系统:
    定义: 所有渠道的订单(线上+线下)
    范围: 包含线下补录订单
    时间: 用 record_time(录入CRM时间)
 
  → 同一指标三个值,业务方挑一个对自己有利的就吵起来

方案一:定义权威源(Source of Truth)

MDM的第一步是"确权"——每个业务对象只能有一个权威源,其他系统都是这个源的下游。这一步是治理工作,需要数据团队联合业务方拍板。

确权矩阵示例(订单业务):
 
  字段             | 权威源         | 下游使用方
  ─────────────────┼────────────────┼─────────────────
  order_id         | 交易系统       | 风控/CRM/数仓
  user_id          | 用户中心       | 所有
  amount           | 交易系统       | 风控/数仓
  status           | 交易系统       | CRM/数仓
  risk_score       | 风控系统       | 数仓
  channel          | 交易系统       | CRM/数仓
  customer_segment | CRM系统        | 数仓
 
  原则:
  - 每个字段只有一个权威源
  - 下游系统读取时必须从权威源同步,不能自己改
  - 同一字段在两个系统不一致时,以权威源为准
  - 字段口径变更必须由权威源系统的Owner发起

落地难点:业务方往往不愿意承认"我不是权威源"。数据团队要带着业务诉求和数据证据去推,比如"上月差异导致大盘错了X次,建议交易系统作为订单权威源"。

方案二:ID Mapping打通

各系统的同一个业务对象往往用不同ID(交易系统的order_id、风控系统的risk_id、CRM的biz_no)。采集层必须建ID Mapping表把它们关联起来。

-- ID Mapping表(主数据核心)
CREATE TABLE id_mapping_order (
  global_order_id BIGINT,           -- 全局唯一ID(数仓自己生成)
  trade_order_id  BIGINT,           -- 交易系统ID
  risk_id         STRING,           -- 风控系统ID
  crm_biz_no      STRING,           -- CRM业务编号
  oms_id          STRING,           -- OMS订单ID
  first_seen_ts   BIGINT,
  last_updated_ts BIGINT
);
 
-- 维护逻辑:用CDC采集各系统订单创建/更新事件
-- 通过共有字段(比如user_id+amount+create_time)做模糊匹配关联
MERGE INTO id_mapping_order t
USING (
  SELECT trade_order_id, risk_id, crm_biz_no
  FROM (
    SELECT 
      tr.order_id AS trade_order_id,
      rk.id AS risk_id,
      cm.biz_no AS crm_biz_no,
      ROW_NUMBER() OVER (PARTITION BY tr.order_id ORDER BY rk.create_time) AS rn
    FROM ods_trade tr
    LEFT JOIN ods_risk rk ON tr.user_id = rk.user_id
      AND ABS(tr.amount - rk.amount) < 0.01
      AND ABS(tr.create_time - rk.check_time) < 60  -- 1分钟内匹配
    LEFT JOIN ods_crm cm ON tr.order_id = cm.ref_order_id
  ) WHERE rn = 1
) s ON t.trade_order_id = s.trade_order_id
WHEN MATCHED THEN UPDATE SET t.risk_id = s.risk_id, t.crm_biz_no = s.crm_biz_no
WHEN NOT MATCHED THEN INSERT (global_order_id, trade_order_id, risk_id, crm_biz_no, ...)
  VALUES (NEXTVAL('seq_global_order'), s.trade_order_id, s.risk_id, s.crm_biz_no, ...);

适用场景:各系统ID不通用,但有可关联的公共字段(user_id+时间戳+金额等)。

方案三:One ID + 融合宽表

ID Mapping打通后,DWD层做"融合"——以权威源为骨干,其他系统补充字段,生成一张统一的订单宽表。下游所有报表只读这张表。

-- DWD融合宽表(单一事实表)
INSERT OVERWRITE TABLE dwd_order_unified PARTITION (ds='20240315')
SELECT
  m.global_order_id,
  -- 来自交易系统(权威源)
  t.order_id, t.user_id, t.amount, t.status, t.create_time, t.channel,
  -- 来自风控系统(补充)
  r.risk_score, r.risk_decision, r.risk_check_time,
  -- 来自CRM(补充)
  c.customer_segment, c.assigned_sales,
  -- 数据质量标记
  CASE WHEN r.risk_id IS NULL THEN 'missing_risk' ELSE 'ok' END AS risk_status,
  CASE WHEN c.crm_biz_no IS NULL THEN 'missing_crm' ELSE 'ok' END AS crm_status
FROM id_mapping_order m
JOIN dwd_trade_orders t ON m.trade_order_id = t.order_id
  AND t.ds = '20240315'
LEFT JOIN dwd_risk_records r ON m.risk_id = r.id
  AND r.ds BETWEEN '20240314' AND '20240316'  -- 兼容跨日
LEFT JOIN dwd_crm_orders c ON m.crm_biz_no = c.biz_no
  AND c.ds BETWEEN '20240314' AND '20240316';

MDM体系对比

阶段做法数据质量落地难度
无治理各系统独立采集低(口径不一)0
指标统一数仓加工时口径对齐中中(治理痛苦)
MDM初级确权+ID Mapping高中
MDM完整+主数据平台+数据血缘极高高(平台投入)

面试高频追问

追问一:业务方就是不愿意配合MDM治理怎么办?

常见困境,靠三招破局:① 用具体case打动决策层(一次大盘错算导致XX损失);② 找一个有强烈痛点的业务方做试点(比如财务对账老对不上的);③ 给业务方提供"治理收益"——比如打通后他们能直接复用其他系统的数据,不用重复开发。光讲规范没人听,要让业务方看到"自己也能受益"。

追问二:模糊匹配的ID Mapping怎么保证准确率?

分层置信度:① 强匹配——共同主键直接关联,置信度100%;② 中匹配——多字段(user_id+amount+time)联合匹配,置信度95%+,加阈值控制(金额误差<0.01、时间误差<60秒);③ 弱匹配——只有少量字段匹配,置信度<90%的标记为"待人工核对"。生产上强匹配能覆盖80%+,剩下的弱匹配每天产出一份报表给业务方人工修正。

追问三:权威源系统挂了怎么办?

两层兜底:① 数仓侧保留前一天快照,权威源挂了用T-1数据兜底;② 关键字段做"多源回填",比如交易系统挂了,用风控系统的amount临时顶上(标记数据来源标识),等权威源恢复后用真实值覆盖。这种降级方案要在SLA里写清楚,不能临时拍脑袋。

实战踩坑:ID Mapping因CDC延迟漏关联

有次发现日订单宽表里有大量"missing_risk"——风控字段为空。排查不是风控系统漏了,而是ID Mapping用T+1批做的,但风控CDC延迟了20分钟,凌晨0点跑Mapping时风控数据还没到,全没匹配上。后来把Mapping改成实时(Flink)+ T+1兜底(Spark),延迟到的数据后补,问题解决。

-- ❌ 反模式:纯T+1批跑Mapping
-- 凌晨2点跑,但风控CDC延迟到凌晨2:30才追平
INSERT INTO id_mapping_order ...   -- 漏掉0:00-2:00产生但2:30才到的数据
 
-- ✓ 正确:实时Mapping + T+1兜底
-- 1) Flink实时关联(主链路)
SELECT t.order_id, r.risk_id
FROM trade_stream t
JOIN risk_stream r WITHIN INTERVAL '1' HOUR
  ON t.user_id = r.user_id AND ABS(t.amount - r.amount) < 0.01
 
-- 2) T+2跑批兜底,补昨天延迟到的数据
MERGE INTO id_mapping_order m
USING (
  SELECT t.order_id, r.id FROM ods_trade t
  JOIN ods_risk r ON ...
  WHERE t.ds = '${bizdate-1}'  -- T-1数据,等所有CDC追平
    AND NOT EXISTS (SELECT 1 FROM id_mapping_order WHERE trade_order_id = t.order_id AND risk_id IS NOT NULL)
) s ON m.trade_order_id = s.order_id
WHEN MATCHED THEN UPDATE SET m.risk_id = s.id;

解决方案:Lambda架构兜底——实时链路保证99%数据,T+1批兜底剩下的延迟数据。同时给"missing_xxx"字段加监控,比例超阈值就告警。这套机制让数据完整率稳定在99.95%+。

总结

主数据治理本质是"组织协同问题伪装成的技术问题"。核心三步:确权(每个字段一个权威源)、ID Mapping(打通各系统)、One ID融合(DWD一张表)。技术上不复杂,难在跨团队推动。面试时讲"治理思维+落地难点+实际收益",比讲技术细节分高得多。

下一篇聊CDC到Kafka的工具选型:Kafka Connect和Flink CDC到底用哪个更稳?

你们公司MDM做到什么程度了?最大的阻力是什么?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器