- 在整个数仓模型构建中分了3个数据域,其中每个数据域对应的业务过程都是什么? dim表没开发过
- DWD层的开发步骤
- 维度退化
- DWM公皇WM是在开发公用层吗、跟DWD层的区别
- DWM是在做一些业务的串联还是基于一个业务?
- 看板代码1000降到100,你的贡献
- 在做DWM中间层替换时要注意的核心点
- 做完新看板替换旧看板时要考虑什么东西,迭代标准是什么?
- 数据一致性上有保障吗?DQC?
- 新增DWM中间表后,因为会涉及读写过程,面板产出的时效性。链路会变长,怎么保证产出的时效性
- 数据优化:join数据倾斜的现象、处理方案
1. 在整个数仓模型构建中分了3个数据域,其中每个数据域对应的业务过程都是什么?(已知dim表未开发)
考察知识点
- 数据域划分的核心逻辑(业务导向、不重叠、可度量)
- 数据域与业务过程的映射关系(业务过程需对应具体可量化的业务活动)
- 无dim表场景下的数据域设计(聚焦业务过程本身,暂不涉及维度关联细节)
参考回答
假设数仓按“企业核心业务链路”划分3个数据域(以电商场景为例,通用且贴合常见业务),分别为交易域、用户域、商品域。因dim表未开发,每个数据域的业务过程聚焦“原始业务活动”,暂不涉及维度关联,具体如下:
数据域 | 核心业务过程(可量化的业务活动) | 业务活动说明(无dim表时的原始数据记录) |
交易域 | 1. 订单创建<br>2. 订单支付<br>3. 订单履约(发货/签收)<br>4. 订单退款 | 1. 订单创建:记录用户提交订单的原始信息(order_id、user_id、goods_ids、amount、create_time等);<br>2. 订单支付:记录支付流水(pay_id、order_id、pay_amount、pay_time、pay_channel等);<br>3. 订单履约:记录物流状态变更(logistics_id、order_id、deliver_time、sign_time、status等);<br>4. 订单退款:记录退款申请与审核(refund_id、order_id、refund_amount、apply_time、audit_time等)。 |
用户域 | 1. 用户注册<br>2. 用户登录<br>3. 用户信息修改<br>4. 用户互动(浏览/收藏/加购) | 1. 用户注册:记录用户账号创建(user_id、register_phone、register_channel、register_time等);<br>2. 用户登录:记录登录行为(login_id、user_id、login_device、login_time、ip等);<br>3. 用户信息修改:记录资料变更(user_id、update_field、old_value、new_value、update_time等);<br>4. 用户互动:记录行为轨迹(behavior_id、user_id、goods_id、behavior_type、behavior_time等)。 |
商品域 | 1. 商品创建(上架)<br>2. 商品库存变动<br>3. 商品价格调整<br>4. 商品评价提交 | 1. 商品创建:记录商品上架信息(goods_id、goods_name、category_id、specs、create_time等);<br>2. 库存变动:记录入库/出库(inventory_id、goods_id、change_type、change_num、operate_time等);<br>3. 价格调整:记录定价变更(price_id、goods_id、old_price、new_price、effect_time等);<br>4. 商品评价:记录用户评分(comment_id、user_id、goods_id、score、content、comment_time等)。 |
补充注意要点
- 业务过程需“可量化”:每个过程必须产生可统计的数据(如“订单创建”对应“订单量”“订单金额”指标),避免抽象描述(如“用户购物”需拆分为“浏览、加购、下单”等具体过程);
- 无dim表的适配:因未开发dim表,业务过程记录需保留原始标识(如
category_id
而非“品类名称”),后续dim表开发后再通过id
关联补充维度属性; - 域间边界清晰:避免业务过程跨域(如“订单支付”属交易域,“用户支付账号绑定”属用户域),确保数据域的独立性。
2. DWD层的开发步骤
考察知识点
- DWD层的核心定位(清洗后的明细数据,为上层提供基础)
- 从ODS到DWD的全流程处理逻辑(清洗、标准化、基础加工)
- 无dim表场景下的DWD层适配(暂不涉及维度关联,聚焦数据本身的规范化)
参考回答
DWD(明细数据层)是数仓的“数据清洗与标准化中心”,核心目标是将ODS层的原始数据转化为“干净、规整、可复用”的明细数据。因dim表未开发,步骤中暂不包含维度关联,具体分为6步:
步骤1:需求与源数据分析
- 明确上游需求:与DWM/DWS层开发人员对齐,确定DWD表需保留的核心字段(如交易域DWD表需包含
order_id
、user_id
、amount
等,暂不要求关联“用户名”); - 分析ODS源数据:梳理ODS层表结构(如MySQL业务表、日志文件),明确字段含义、数据类型、异常值规则(如
amount<0
的订单属无效数据,create_time
晚于当前时间的记录属异常); - 输出《DWD层需求规格说明书》,包含表名、字段清单、数据来源(如ODS层
ods_trade_order
)、更新频率(T+1全量/增量)。
步骤2:DWD表结构设计
- 字段命名规范:采用“业务域_字段含义”格式(如
trade_amount
表示交易金额,user_login_time
表示用户登录时间),避免模糊命名(如col1
); - 数据类型标准化:
- 日期字段统一为
datetime
(格式yyyy-MM-dd HH:mm:ss
),避免varchar
存储(如ODS层create_time
为20231001
,DWD层转为2023-10-01 00:00:00
); - 数值字段:金额用
decimal(10,2)
,数量用bigint
,避免float
(防止精度丢失);
- 日期字段统一为
- 分区设计:按时间分区(如
dt
字段,格式yyyyMMdd
),支持按时间范围查询;大表可叠加业务字段分区(如交易表按dt+pay_channel
分区); - 存储格式:选择ORC/Parquet(列存格式,支持压缩和列裁剪,减少后续查询IO)。
步骤3:数据清洗(核心步骤)
- 过滤无效数据:
- 空值过滤:删除核心字段(如
order_id
、user_id
)为null的记录; - 异常值过滤:删除
amount<0
的订单、login_time
早于register_time
的登录记录;
- 空值过滤:删除核心字段(如
- 去重处理:
- 针对日志数据(如用户行为日志),通过
row_number() over (partition by 唯一键 order by 时间戳 desc) = 1
删除重复记录(如因采集重试导致的重复行); - 针对业务表,通过主键(如
order_id
)去重,保留最新版本记录;
- 针对日志数据(如用户行为日志),通过
- 格式标准化:
- 统一编码:如用户手机号去除空格、特殊字符(
138 0013 8000
转为13800138000
); - 枚举值统一:如订单状态“0/1/2”统一标注为“待支付/已支付/已取消”(便于后续理解,暂不涉及维度表);
- 统一编码:如用户手机号去除空格、特殊字符(
- 脱敏处理:对敏感字段进行加密或替换(如用户手机号中间4位替换为
*
,即1388000
;身份证号保留首尾6位)。
步骤4:基础数据补全(无dim表适配)
- 因dim表未开发,暂不进行维度关联,仅对缺失的业务字段补充默认值:
- 如
pay_channel
为null时,补充为“未知渠道”; goods_specs
(商品规格)为空时,补充为“无规格”;
- 如
- 保留原始业务标识(如
category_id
、brand_id
),待后续dim表开发后再关联补充名称、属性等信息。
步骤5:代码开发与测试
- 开发工具:使用Hive SQL/Spark SQL编写ETL脚本,实现清洗、去重、标准化逻辑;
- 示例(交易域DWD表清洗脚本片段):
- 测试验证:
- 数据量校验:DWD表数据量应略小于ODS层(差值为过滤的无效/重复数据量,通常差异<5%);
- 数据质量校验:核心字段空值率<0.1%,格式标准化率100%(如所有日期字段均为
yyyy-MM-dd HH:mm:ss
); - 逻辑校验:如
pay_time
(若存在)需≥create_time
,refund_amount
≤amount
。
INSERT OVERWRITE TABLE dwd_trade_order PARTITION (dt='${dt}')
SELECT
order_id,
user_id,
goods_ids,
-- 金额异常值处理
CASE WHEN amount < 0 THEN 0 ELSE amount END AS amount,
-- 状态标准化
CASE order_status
WHEN 0 THEN '待支付'
WHEN 1 THEN '已支付'
WHEN 2 THEN '已取消'
ELSE '未知' END AS order_status,
-- 时间格式标准化
FROM_UNIXTIME(unix_timestamp(create_time, 'yyyyMMddHHmmss'), 'yyyy-MM-dd HH:mm:ss') AS create_time
FROM ods_trade_order
WHERE dt='${dt}'
-- 过滤空值
AND order_id IS NOT NULL
AND user_id IS NOT NULL
-- 去重
QUALIFY row_number() over (partition by order_id order by create_time desc) = 1;
步骤6:调度部署与监控
- 调度配置:通过Airflow/DolphinScheduler配置任务调度,设置依赖关系(如DWD层任务需在ODS层数据同步完成后执行);
- 监控告警:
- 数据量监控:若DWD表数据量较前一日波动超30%,触发企业微信告警;
- 执行时间监控:确保T+1任务在每日6点前完成(不影响上层DWM/DWS表生成);
- 数据质量监控:通过脚本每日检查字段空值率、格式正确性,生成《DWD层数据质量报告》。
补充注意要点
- 复用性优先:DWD表需支撑多个DWM/DWS表,避免按单一上层需求定制字段(如交易域DWD表需包含所有订单相关明细字段,而非仅包含某报表需要的字段);
- 轻量加工:因dim表未开发,暂不进行复杂业务逻辑计算(如用户活跃度、商品销量排名),仅做数据清洗与标准化,复杂加工留到DWM层(待dim表开发后结合维度关联);
- 数据溯源:保留ODS层原始字段标识(如
ods_order_id
),便于后续问题排查(如DWS层数据异常时,可追溯至ODS层原始数据)。
3. 维度退化
考察知识点
- 维度退化的定义与核心逻辑(将维度属性融入事实表,减少关联)
- 维度退化的适用场景(与维度表特性、业务需求匹配)
- 无dim表场景下的维度退化适配(基于原始业务标识的退化思路)
参考回答
维度退化(Dimension Degeneration)是数仓建模中的优化手段,指将低基数、低变化频率的维度属性(如“支付渠道”“商品品类”)直接冗余到事实表中,不再单独维护维度表(或暂用原始标识替代),从而减少查询时的表关联次数,提升效率。因dim表未开发,维度退化需基于原始业务标识和基础属性实现,具体如下:
(1)核心逻辑与目的
- 传统建模(有dim表):事实表(如
dwd_trade_order
)需关联维度表(如dim_pay_channel
)才能获取“支付渠道名称”,查询时需执行join
操作; - 维度退化(无dim表):直接在事实表中保留“支付渠道标识”(如
pay_channel=1
代表微信支付),并冗余基础属性(如pay_channel_name='微信支付'
,暂通过硬编码或配置表补充),查询时无需关联维度表,直接过滤pay_channel_name='微信支付'
。
核心目的:在“数据冗余”与“查询效率”之间平衡,通过少量冗余(低基数维度属性占用存储空间小)换取查询性能提升,尤其适配dim表未开发时“无法关联维度表”的场景。
(2)适用场景(无dim表适配)
维度退化需满足“低基数、低变化、高频关联”三大条件,结合无dim表场景,具体适用场景:
- 低基数维度:维度属性取值数量少(如“支付渠道”仅3类:微信/支付宝/现金,对应
pay_channel=1/2/3
),冗余后不会显著增加事实表存储; - 低变化频率:维度属性长时间不变(如“商品品类”一旦确定,半年内不会修改,
category_id=1
始终对应“食品”),无需频繁更新事实表中的冗余字段; - 高频关联需求:该维度需被大量查询频繁用于筛选或聚合(如“按支付渠道统计销售额”“按商品品类分析订单量”),退化后可避免因无dim表导致的“无法关联”问题。
(3)不适用场景(无dim表适配)
- 高基数维度:维度属性取值数量多(如
user_id
达百万级、goods_id
达千万级),冗余后会导致事实表体积暴增(如1亿条订单表,每条冗余user_id
会增加约4GB存储); - 高变化频率:维度属性频繁变更(如“商品价格”每日更新、“用户等级”实时变动),若冗余到事实表,需频繁更新历史数据(如商品价格变更后,需重新计算所有包含该商品的订单记录),维护成本极高;
- 多值维度:一个事实记录对应多个维度值(如“订单包含多个商品品类”),无法将多值冗余到单一字段,需单独维护关联表(如
order_category_rel
)。
(4)无dim表场景下的退化实现示例
以交易域dwd_trade_order
表为例,实现“支付渠道”维度退化:
- ODS层原始数据:仅包含
pay_channel=1/2/3
(无渠道名称); - DWD层退化处理:通过
case when
硬编码补充渠道名称(暂代dim表功能),冗余到事实表: - 查询效果:分析“微信支付订单占比”时,直接查询DWD表,无需关联dim表:
SELECT
dt,
COUNT(CASE WHEN pay_channel_name='微信支付' THEN order_id END) / COUNT(order_id) AS wechat_pay_ratio
FROM dwd_trade_order
GROUP BY dt;
SELECT
order_id,
user_id,
amount,
pay_channel, -- 原始标识(1/2/3)
-- 维度退化:冗余支付渠道名称(暂代dim_pay_channel表)
CASE pay_channel
WHEN 1 THEN '微信支付'
WHEN 2 THEN '支付宝支付'
WHEN 3 THEN '现金支付'
ELSE '未知渠道' END AS pay_channel_name,
create_time
FROM ods_trade_order
WHERE dt='${dt}';
补充注意要点
- 过渡性适配:无dim表时的维度退化(如硬编码补充名称)是临时方案,后续dim表开发后,需替换为“事实表关联dim表”的标准模式,避免硬编码导致的维护困难(如新增支付渠道时需修改DWD层脚本);
- 冗余字段命名规范:退化的维度属性字段需明确标识(如
pay_channel_name
而非channel_name
),与原始标识(pay_channel
)区分,便于后续替换; - 避免过度退化:仅退化“高频关联、低基数、低变化”的维度属性,不盲目冗余所有维度(如
user_id
是高基数维度,不可退化)。
4. DWM是在开发公用层吗?跟DWD层的区别
考察知识点
- DWM层的定位(公用中间层的核心特征:复用性、通用化)
- DWM与DWD层的核心差异(加工程度、粒度、用途、业务逻辑)
- 无dim表场景下两层的适配调整
参考回答
DWM(中间数据层)属于数仓的“公用中间层”,核心为上层DWS层和业务应用提供“通用化、可复用的中间加工结果”,减少重复计算;其与DWD层(明细数据层)在定位、加工程度等方面差异显著,即使在无dim表场景下,核心区别仍清晰:
(1)DWM层是典型的公用层
数仓中的“公用层”指为多个下游模块(如不同DWS主题表、不同业务报表)提供共享数据的层级,避免各模块重复开发相同逻辑。DWM层的公用性体现在:
- 一次加工,多次复用:例如开发
dwm_trade_order_hourly
(交易小时表),包含“每小时各支付渠道订单量、金额”,可同时支撑DWS层的“日交易汇总表”“支付渠道分析表”,无需各DWS表单独计算小时级指标; - 通用业务逻辑封装:将高频使用的业务逻辑(如“有效订单”定义为“
amount>0
且order_status!='已取消'
”)在DWM层统一处理,下游直接引用,避免口径不一致(如A报表和B报表对“有效订单”定义不同)。
即使无dim表,DWM层仍需聚焦“通用化加工”,例如将“用户登录行为”和“下单行为”关联,生成“登录-下单转化中间表”,支撑多个下游转化分析场景。
(2)DWM层与DWD层的核心区别(无dim表适配)
对比维度 | DWM层(中间数据层) | DWD层(明细数据层) |
核心定位 | 公用中间加工层,为上层提供可复用的中间结果 | 明细数据层,为上层提供干净、规整的原始明细 |
加工程度 | 轻度聚合+业务逻辑加工(如按小时/渠道聚合订单量、计算登录-下单转化率) | 仅做清洗、标准化、基础补全(无聚合,保留原始明细粒度) |
数据粒度 | 中等粒度(介于明细与汇总之间,如 dt+hour+pay_channel 、user_id+dt ) | 最细粒度(与源数据一致,如 order_id 级、behavior_id 级) |
业务逻辑 | 包含通用业务规则(如“有效订单”定义、“活跃用户”判定为“当日登录≥1次”) | 无业务规则,仅做数据标准化(如日期格式统一、空值填充) |
复用性 | 高(一个DWM表支撑多个DWS表/报表,减少重复计算) | 极高(所有上层表均依赖DWD表,是数仓的“地基”) |
无dim表适配 | 基于原始标识加工(如按 pay_channel 聚合,暂用pay_channel_name 退化属性) | 保留原始标识+退化基础属性(如 pay_channel +pay_channel_name ),暂不关联维度表 |
补充注意要点
- 边界不可混淆:DWD层不做聚合,DWM层不做明细存储,即使无dim表,也需严格按“明细清洗”与“中间聚合”划分职责,避免DWD层包含聚合逻辑(如按渠道统计订单量);
- 无dim表的临时适配:DWM层加工时,若需维度属性(如“商品品类名称”),可暂用DWD层退化的属性(如
category_name
),后续dim表开发后替换为关联查询,确保逻辑可迁移; - 性能优化核心:DWM层的公用性本质是“减少重复计算”,尤其在大数据量场景下(如每日1亿条订单),一次聚合可节省后续多次重复扫描明细数据的开销,提升数仓整体效率。
5. DWM是在做一些业务的串联还是基于一个业务?
考察知识点
- DWM层的业务覆盖范围(单一业务深化 vs 跨业务串联)
- 中间层加工的核心逻辑(按需选择加工方式,匹配上层需求)
- 无dim表场景下的业务加工适配
参考回答
DWM层的核心目标是“提供通用化中间结果”,因此既会基于单一业务做深化加工,也会跨多个业务做串联整合,具体选择取决于上层DWS层和业务报表的需求。即使在无dim表场景下,仍可通过原始业务标识实现业务串联,两者的定位与实现如下:
(1)基于单一业务的深化加工
当上层需求聚焦某一业务域的细粒度分析时,DWM层会对单一业务过程做“深化加工”,核心是“细化粒度、封装业务逻辑”,不涉及其他业务域数据。
- 适用场景:需对某业务过程做高频细粒度查询(如“订单每小时状态变化分析”“用户每日登录行为分析”);
- 无dim表适配示例(交易域单一业务加工):基于DWD层
dwd_trade_order
(订单明细),开发DWM层dwm_trade_order_status_hourly
(订单小时状态表),按“dt+hour+order_status
”聚合,封装“订单状态流转”逻辑: - 价值:支撑DWS层“订单状态日汇总”“订单履约效率分析”等多个报表,无需重复计算小时级状态数据。
(2)跨业务的串联整合
当上层需求需要分析多个业务域的关联关系(如“用户登录后多久下单”“商品浏览后加购转化率”)时,DWM层会“串联多个业务域数据”,核心是“关联不同业务过程,生成综合中间结果”。
- 适用场景:需跨业务域的转化分析、用户行为路径分析等(如“用户生命周期价值(LTV)分析”需关联用户注册、登录、下单、支付等多个业务);
- 无dim表适配示例(用户域与交易域串联):关联DWD层
dwd_user_login
(用户登录明细)和dwd_trade_order
(订单明细),开发DWM层dwm_user_login_order
(用户登录-下单转化表),计算“登录后1小时内下单转化率”: - 价值:支撑DWS层“用户登录转化漏斗”“高转化用户特征分析”等报表,避免每次分析都重复关联登录和订单表。
(3)选择依据:上层需求导向
DWM层选择“单一业务深化”还是“跨业务串联”,完全由上层需求决定:
- 若上层需求以“业务域内分析”为主(如交易域的订单履约效率、商品域的库存周转),则侧重单一业务加工;
- 若上层需求以“用户为中心的综合分析”为主(如用户行为路径、转化漏斗),则侧重跨业务串联;
This post is for subscribers on the 网站会员 and 成为小万的高级会员 tiers only
Subscribe NowAlready have an account? Sign In