DWD(Data Warehouse Detail)层是数据仓库体系中的明细数据层,位于ODS(Operational Data Store,原始数据层)之上,DIM(维度层)和DWS(数据服务层)之下。它是数据仓库的核心加工区域,承担着将原始数据转换为可用分析数据的重要职责。
DWD层的主要特点是:
1、面向主题:按业务领域进行数据组织 2、粒度统一:保持相同业务过程的数据粒度一致 3、结构规范:字段命名和定义遵循统一标准 4、历史完整:保留历史变更数据,确保可追溯性
DWD层建设的基本思路
1、业务分域设计
DWD层首先应该按照业务域(Domain)进行划分,常见的业务域包括:用户域:用户基础信息、注册、登录、地址等
商品域:商品、类目、品牌等基础数据 交易域:订单、支付、退款等交易过程数据 流量域:点击、曝光、跳出等用户行为数据 营销域:活动、优惠券、秒杀等营销数据 库存域:库存、仓储等供应链数据 互动域:评论、收藏、分享等社交数据
这种分域方式让数据架构更清晰,方便不同业务部门使用自己关心的数据。
2、明确数据模型类型
DWD层主要包含两类数据模型:
事实表:记录业务事件,通常包含度量值和外键 维度表:描述业务对象的属性,如用户、商品、时间等
根据数据更新方式,DWD表可以分为:
全量表(Full):每次加载会覆盖所有历史数据 增量表(Inc):只加载新增或变化的数据 拉链表:记录数据的历史变更,保留所有版本信息
3、数据加工规范
DWD层的数据加工遵循以下规范:字段规范:统一字段命名和数据类型,如id、create_time等
数据清洗:处理空值、异常值、重复值等 数据转换:类型转换、编码转换、格式标准化 数据整合:关联多个来源的数据,丰富信息维度 指标计算:生成基础派生指标
4、分区与性能优化
为提高查询效率,DWD层通常采用分区策略: 按时间分区:最常见的方式,如按天分区(k1字段) 按业务分区:某些场景下按业务线或地区分区 复合分区:时间+业务的组合分区策略
DWD层建设实践案例 - 用户地址表设计与实现
下面以dwd_user_address_full表为例,详细说明DWD层表的设计和实现过程。
1、需求分析
用户地址信息是电商系统的重要基础数据,需要支持:
用户历史地址查询 配送范围分析 区域销售分布统计
2、数据源分析
从ODS层,我们有两个相关表:
ods_user_address_full:用户地址基本信息 ods_base_province_full:省份信息
通过分析表结构,发现:
用户地址表包含用户ID、省份ID等基本信息 省份表包含省份名称、地区编码等信息 缺少专门的城市和区县表
3、表结构设计
CREATE TABLE dwd.dwd_user_address_full ( `id` VARCHAR(255) COMMENT '地址ID', `k1` DATE COMMENT '数据日期', `user_id` STRING COMMENT '用户ID', `province_id` STRING COMMENT '省份ID', `province_name` STRING COMMENT '省份名称', `city_id` STRING COMMENT '城市ID', `city_name` STRING COMMENT '城市名称', `district_id` STRING COMMENT '区县ID', `district_name` STRING COMMENT '区县名称', `detail_address` STRING COMMENT '详细地址', `consignee` STRING COMMENT '收货人', `phone_num` STRING COMMENT '联系电话', `is_default` STRING COMMENT '是否默认地址', `create_time` DATETIME COMMENT '创建时间', `operate_time` DATETIME COMMENT '操作时间', `postal_code` STRING COMMENT '邮政编码', `full_address` STRING COMMENT '完整地址' ) ENGINE=OLAP UNIQUE KEY(`id`, `k1`) DISTRIBUTED BY HASH(`id`);
4、ETL实现
-- 用户域用户地址全量表 INSERT INTO dwd.dwd_user_address_full(id, k1, user_id, province_id, province_name, city_id, city_name, district_id, district_name, detail_address, consignee, phone_num, is_default, create_time, operate_time, postal_code, full_address) select ua.id, date('${pdate}') as k1, -- 使用参数日期作为k1值 ua.user_id, ua.province_id, bp.name as province_name, ua.city_id, bp.area_code as city_name, -- 这里假设使用area_code作为城市名称,实际应根据实际情况调整 ua.district_id, bp.iso_code as district_name, -- 这里假设使用iso_code作为区域名称,实际应根据实际情况调整 ua.user_address as detail_address, -- 将user_address字段映射为detail_address ua.consignee, ua.phone_num, ua.is_default, now() as create_time, -- 使用当前时间作为create_time now() as operate_time, -- 使用当前时间作为operate_time null as postal_code, -- 暂无此数据,可根据实际情况调整 concat(bp.name, ' ', bp.area_code, ' ', bp.iso_code, ' ', ua.user_address) as full_address -- 完整地址拼接 from ( select id, user_id, province_id, province_id as city_id, -- 暂用province_id代替city_id province_id as district_id, -- 暂用province_id代替district_id user_address, consignee, phone_num, is_default from ods.ods_user_address_full ) ua left join ( select id, name, area_code, iso_code from ods.ods_base_province_full ) bp on ua.province_id = bp.id;
DWD层建设的经验总结
1、统一规范先行:在开始建设前,制定统一的命名规范和数据标准 2、分阶段建设:先搭建核心业务域,后扩展其他业务域 3、灵活处理数据缺失:面对不完美的数据源,使用合理的替代方案 4、重视文档和注释:详细记录表结构、字段含义和处理逻辑 5、持续优化:随着业务发展,不断完善DWD层数据模型
还没有评论,来说两句吧...