数仓搭建DWD层

1、数仓DWD层

1)对用户行为数据解析。

2)对业务数据采用维度模型重新建模。

2、DWD层(用户行为日志)

2.1、日志解析思路

(1)页面埋点日志
请添加图片描述

(2)启动日志
请添加图片描述

解析思路
请添加图片描述

2.2、get_json_object函数使用

1)数据

[{"name":"大郎","sex":"男","age":"25"},{"name":"西门庆","sex":"男","age":"47"}]

2)取出第一个json对象

hive (gmall)>
select get_json_object('[{"name":"大郎","sex":"男","age":"25"},{"name":"西门庆","sex":"男","age":"47"}]','$[0]');

3)取出第一个json的age字段的值

hive (gmall)>
SELECT get_json_object('[{"name":"大郎","sex":"男","age":"25"},{"name":"西门庆","sex":"男","age":"47"}]',"$[0].age");

结果是:25

2.3、启动日志表

启动日志解析思路:启动日志表中每行数据对应一个启动记录,一个启动记录应该包含日志中的公共信息和启动信息。先将所有包含start字段的日志过滤出来,然后使用get_json_object函数解析每个字段。

2.3.1、建表语句

DROP TABLE IF EXISTS dwd_start_log;
CREATE EXTERNAL TABLE dwd_start_log(
    `area_code` STRING COMMENT '地区编码',
    `brand` STRING COMMENT '手机品牌',
    `channel` STRING COMMENT '渠道',
    `is_new` STRING COMMENT '是否首次启动',
    `model` STRING COMMENT '手机型号',
    `mid_id` STRING COMMENT '设备id',
    `os` STRING COMMENT '操作系统',
    `user_id` STRING COMMENT '会员id',
    `version_code` STRING COMMENT 'app版本号',
    `entry` STRING COMMENT 'icon手机图标 notice 通知 install 安装后启动',
    `loading_time` BIGINT COMMENT '启动加载时间',
    `open_ad_id` STRING COMMENT '广告页ID ',
    `open_ad_ms` BIGINT COMMENT '广告总共播放时间',
    `open_ad_skip_ms` BIGINT COMMENT '用户跳过广告时点',
    `ts` BIGINT COMMENT '时间'
) COMMENT '启动日志表'
PARTITIONED BY (`dt` STRING) -- 按照时间创建分区
STORED AS PARQUET -- 采用parquet列式存储
LOCATION '/warehouse/gmall/dwd/dwd_start_log' -- 指定在HDFS上存储位置
TBLPROPERTIES('parquet.compression'='lzo') -- 采用LZO压缩
;

2.3.2、数据导入

请添加图片描述

hive (gmall)> 
insert overwrite table dwd_start_log partition(dt='2022-04-11')
select
    get_json_object(line,'$.common.ar'),
    get_json_object(line,'$.common.ba'),
    get_json_object(line,'$.common.ch'),
    get_json_object(line,'$.common.is_new'),
    get_json_object(line,'$.common.md'),
    get_json_object(line,'$.common.mid'),
    get_json_object(line,'$.common.os'),
    get_json_object(line,'$.common.uid'),
    get_json_object(line,'$.common.vc'),
    get_json_object(line,'$.start.entry'),
    get_json_object(line,'$.start.loading_time'),
    get_json_object(line,'$.start.open_ad_id'),
    get_json_object(line,'$.start.open_ad_ms'),
    get_json_object(line,'$.start.open_ad_skip_ms'),
    get_json_object(line,'$.ts')
from ods_log
where dt='2022-04-11'
and get_json_object(line,'$.start') is not null;
3)查看数据
hive (gmall)> 
select * from dwd_start_log where dt='2022-04-11' limit 2;

2.3.3、查看数据

hive (gmall)> 
select * from dwd_start_log where dt='2022-04-11' limit 2;

2.4、页面日志表

页面日志解析思路:页面日志表中每行数据对应一个页面访问记录,一个页面访问记录应该包含日志中的公共信息和页面信息。先将所有包含page字段的日志过滤出来,然后使用get_json_object函数解析每个字段。

2.4.1、建表语句

DROP TABLE IF EXISTS dwd_page_log;
CREATE EXTERNAL TABLE dwd_page_log(
    `area_code` STRING COMMENT '地区编码',
    `brand` STRING COMMENT '手机品牌',
    `channel` STRING COMMENT '渠道',
    `is_new` STRING COMMENT '是否首次启动',
    `model` STRING COMMENT '手机型号',
    `mid_id` STRING COMMENT '设备id',
    `os` STRING COMMENT '操作系统',
    `user_id` STRING COMMENT '会员id',
    `version_code` STRING COMMENT 'app版本号',
    `during_time` BIGINT COMMENT '持续时间毫秒',
    `page_item` STRING COMMENT '目标id ',
    `page_item_type` STRING COMMENT '目标类型',
    `last_page_id` STRING COMMENT '上页类型',
    `page_id` STRING COMMENT '页面ID ',
    `source_type` STRING COMMENT '来源类型',
    `ts` bigint
) COMMENT '页面日志表'
PARTITIONED BY (`dt` STRING)
STORED AS PARQUET
LOCATION '/warehouse/gmall/dwd/dwd_page_log'
TBLPROPERTIES('parquet.compression'='lzo');

2.4.2、数据导入

hive (gmall)>
insert overwrite table dwd_page_log partition(dt='2022-04-11')
select
    get_json_object(line,'$.common.ar'),
    get_json_object(line,'$.common.ba'),
    get_json_object(line,'$.common.ch'),
    get_json_object(line,'$.common.is_new'),
    get_json_object(line,'$.common.md'),
    get_json_object(line,'$.common.mid'),
    get_json_object(line,'$.common.os'),
    get_json_object(line,'$.common.uid'),
    get_json_object(line,'$.common.vc'),
    get_json_object(line,'$.page.during_time'),
    get_json_object(line,'$.page.item'),
    get_json_object(line,'$.page.item_type'),
    get_json_object(line,'$.page.last_page_id'),
    get_json_object(line,'$.page.page_id'),
    get_json_object(line,'$.page.source_type'),
    get_json_object(line,'$.ts')
from ods_log
where dt='2022-04-11'
and get_json_object(line,'$.page') is not null;

2.4.3、查看数据

hive (gmall)> 
select * from dwd_page_log where dt='2022-04-11' limit 2;

2.5、动作日志表

动作日志解析思路:动作日志表中每行数据对应用户的一个动作记录,一个动作记录应当包含公共信息、页面信息以及动作信息。先将包含action字段的日志过滤出来,然后通过UDTF函数,将action数组“炸开”(类似于explode函数的效果),然后使用get_json_object函数解析每个字段。

2.5.1、建表语句

DROP TABLE IF EXISTS dwd_action_log;
CREATE EXTERNAL TABLE dwd_action_log(
    `area_code` STRING COMMENT '地区编码',
    `brand` STRING COMMENT '手机品牌',
    `channel` STRING COMMENT '渠道',
    `is_new` STRING COMMENT '是否首次启动',
    `model` STRING COMMENT '手机型号',
    `mid_id` STRING COMMENT '设备id',
    `os` STRING COMMENT '操作系统',
    `user_id` STRING COMMENT '会员id',
    `version_code` STRING COMMENT 'app版本号',
    `during_time` BIGINT COMMENT '持续时间毫秒',
    `page_item` STRING COMMENT '目标id ',
    `page_item_type` STRING COMMENT '目标类型',
    `last_page_id` STRING COMMENT '上页类型',
    `page_id` STRING COMMENT '页面id ',
    `source_type` STRING COMMENT '来源类型',
    `action_id` STRING COMMENT '动作id',
    `item` STRING COMMENT '目标id ',
    `item_type` STRING COMMENT '目标类型',
    `ts` BIGINT COMMENT '时间'
) COMMENT '动作日志表'
PARTITIONED BY (`dt` STRING)
STORED AS PARQUET
LOCATION '/warehouse/gmall/dwd/dwd_action_log'
TBLPROPERTIES('parquet.compression'='lzo');

2.5.2、创建UDTF函数

1)设计思路

请添加图片描述
在这里插入图片描述

2)编写代码

(1)创建一个maven工程:hivefunction
(2)创建包名:com.atguigu.hive.udtf
(3)引入如下依赖

<dependencies>
    <!--添加hive依赖-->
    <dependency>
        <groupId>org.apache.hive</groupId>
        <artifactId>hive-exec</artifactId>
        <version>3.1.2</version>
    </dependency>
</dependencies>

(4)编码

package com.atguigu.hive.udtf;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.json.JSONArray;

import java.util.ArrayList;
import java.util.List;

public class ExplodeJSONArray extends GenericUDTF {
   
   

    @Override
    public StructObjectInspector initialize(ObjectInspector[] argOIs) throws UDFArgumentException {
   
   

        // 1 参数合法性检查
        if (argOIs.length != 1) {
   
   
            throw new UDFArgumentException("explode_json_array 只需要一个参数");
        }

        // 2 第一个参数必须为string
        //判断参数是否为基础数据类型
        if (argOIs[0].getCategory() != ObjectInspector.Category.PRIMITIVE) {
   
   
            throw new UDFArgumentException("explode_json_array 只接受基础类型参数");
        }

        //将参数对象检查器强转为基础类型对象检查器
        PrimitiveObjectInspector argumentOI = (PrimitiveObjectInspector) argOIs[0];

        //判断参数是否为String类型
        if (argumentOI.getPrimitiveCategory() != PrimitiveObjectInspector.PrimitiveCategory.STRING) {
   
   
            throw new UDFArgumentException("explode_json_array 只接受string类型的参数");
        }

        // 3 定义返回值名称和类型
        List<String> fieldNames = new ArrayList<String>();
        List<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>();

        fieldNames.add("items");
        fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);

        return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);
    }

    public void process(Object[] objects) throws HiveException {
   
   

        // 1 获取传入的数据
        String jsonArray = objects[0].toString();

        // 2 将string转换为json数组
        JSONArray actions = new JSONArray(jsonArray);

        // 3 循环一次,取出数组中的一个json,并写出
        for (int i = 0; i < actions.length(); i++) {
   
   

            String[] result = new String[1];
            result[0] = actions.getString(i);
            forward(result);
        }
    }

    public void close() throws HiveException {
   
   

    }

}
3)创建函数

(1)打包

(2)将hivefunction-1.0-SNAPSHOT.jar上传到h102的/opt/module,然后再将该jar包上传到HDFS的/user/hive/jars路径下

hadoop fs -mkdir -p /user/hive/jars
hadoop fs -put hivefunction-1.0-SNAPSHOT.jar /user/hive/jars

(3)创建永久函数与开发好的java class关联

create function explode_json_array as 'com.atguigu.hive.udtf.ExplodeJSONArray' using jar 'hdfs://h102:8020/user/hive/jars/hivefunction-1.0-SNAPSHOT.jar';

(4)注意:如果修改了自定义函数重新生成jar包怎么处理?只需要替换HDFS路径上的旧jar包,然后重启Hive客户端即可。

2.5.3、数据导入

insert overwrite table dwd_action_log partition(dt='2022-04-11')
select
    get_json_object(line,'$.common.ar'),
    get_json_object(line,'$.common.ba'),
    get_json_object(line,'$.common.ch'),
    get_json_object(line,'$.common.is_new'),
    get_json_object(line,'$.common.md'),
    get_json_object(line,'$.common.mid'),
    get_json_object(line,'$.common.os'),
    get_json_object(line,'$.common.uid'
<think>嗯,用户想了解大中的DWD、DWS、ADS的区别,特别是DWS的宽表特性。首先,我需要回顾一下的概念,确保自己理解正确。根据用户提供的引用内容,通常分为ODS、DWD、DWS、DWT、ADS等。用户主要关注的是DWD、DWS、ADS这三的区别,以及DWS的宽表特性。 首先,DWD据明细,引用[1]提到DWD做了据清洗、规范化、维度退化等工作。这意味着DWD据是干净的、结构化的,并且可能已经关联了一些维度信息,但仍然是明细据,没有聚合。例如,订单表中的每个订单记录可能包含用户ID、商品ID等,但需要关联用户和商品维度表才能获得更多信息。 接下来是DWS,即服务。根据引用[3],DWS处理的是汇总据,比如用户行为的各种次和金额。用户提到的宽表特性应该是在这一实现的。宽表通常是指将多个相关的事实表和维度表进行关联,生成一张包含大量字段的表,以减少后续查询时的连接操作。例如,用户的行为据(登录、点赞、下单等)可能被汇总到一张宽表中,每个用户对应一行,包含多个指标字段。 然后是ADS,即应用。引用[1]指出ADS对接具体应用需求,提供高度聚合的据。这意味着ADS据已经是高度汇总的,可能直接用于报表、BI工具或API接口。例如,某个应用需要展示每日销售总额,ADS可能已经预先计算好了这些据,以便快速查询。 现在需要明确这三的区别。DWD是明细据,经过清洗和规范化;DWS是汇总据,形成宽表以减少关联操作;ADS是针对具体应用的聚合据。DWS的宽表特性主要体现在其维度整合和指标预聚合上,比如将用户的各种行为指标整合到一张表中,方便后续分析。 用户可能是在学习设计,或者正在准备面试,需要清晰理解各的职责。需要确保回答结构清晰,对比明确,并举例说明宽表的应用场景。同时,需要参考提供的引用内容,确保信息准确,比如引用[2]提到实时计算使用Flink处理ETL,可能影响DWD的实时据处理方式,但用户的问题主要集中在离线的分,所以可能不需要深入实时处理部分。 另外,用户可能存在的疑问包括:为什么需要分?各如何协作?宽表的设计原则是什么?是否所有都需要这些?需要简明扼要地解答这些潜在问题,但用户当前的问题集中在区别和宽表特性,应优先回答这些,再通过相关问题拓展。 需要检查是否有遗漏的关键点,比如DWT(主题)是否与DWS有重叠,但根据引用[1],DWT可能更偏向主题的聚合,而DWS是汇总,可能在粒度上有所不同。不过用户没有提到DWT,所以可以暂时忽略,专注于用户提到的三。 最后,确保回答符合格式要求,使用中文,行内公式用$...$,独立公式用$$...$$,但用户的问题不涉及学公式,可能不需要使用。引用标记需要正确,比如引用[1]、[2]、[3]在适当的位置。例如,在解释DWD时引用[1]提到的清洗和规范化,DWS引用[3]的汇总操作等。</think>### 大详解:DWD、DWS、ADS 的区别与 DWS 宽表特性 #### 一、核心分对比 | 级 | 名称 | 据粒度 | 核心职责 | 典型场景示例 | 引用来源 | |------|---------------------|----------------|--------------------------------------------------------------------------|----------------------------------------------------------------------------|----------| | DWD | 据明细 | **原子粒度** | 清洗脏据、规范化字段、维度退化(如将用户 ID 关联到用户信息) | 原始订单表 → 清洗后订单表(含用户基础信息、商品基础信息) | [^1][^3] | | DWS | 服务 | **主题粒度** | 按主题域预聚合、构建宽表(多维度整合)、生成公共指标 | 用户行为宽表(含登录次、点赞次、下单金额等跨业务线指标) | [^3] | | ADS | 应用 | **应用粒度** | 按业务需求定制化聚合(如报表、接口、算法特征) | 大屏展示的日活用户、营销活动 ROI 分析表 | [^2] | #### 二、DWS 的宽表特性详解 1. **宽表定义** 宽表是通过 **多表关联 + 指标预计算** 生成的宽维度表,通常包含以下特征: - **字段冗余度高**:整合 10+ 个维度(如时间、地域、用户属性) - **指标聚合度深**:预计算留存率、转化漏斗等复杂指标 - **查询性能优化**:通过空间换时间减少 JOIN 操作 2. **设计原则** ```sql -- 示例:用户行为宽表(DWS ) CREATE TABLE dws_user_behavior_wide ( user_id STRING COMMENT '用户ID', dt STRING COMMENT '日期', -- 维度字段(冗余存储) age_group STRING COMMENT '年龄段', city STRING COMMENT '所在城市', -- 行为指标(预聚合) login_count BIGINT COMMENT '当日登录次', order_amount DECIMAL(18,2) COMMENT '当日下单总金额', cart_add_count BIGINT COMMENT '加购次' ) PARTITIONED BY (dt); ``` - **维度整合**:将用户画像、商品类目等维度退化到事实表中[^1] - **时间周期**:按天/周/月等固定周期聚合(如 `dt` 分区字段)[^3] - **业务域划分**:按用户、商品、交易等主题域构建独立宽表[^2] 3. **技术价值** - **查询提速**:BI 工具直接查询宽表,响应时间从分钟级降至秒级[^2] - **计算资源节省**:避免重复计算公共指标(如日活用户被多个应用复用) - **据一致性**:通过统一加工逻辑消除指标二义性(如 GMV 的计算口径) #### 三、分协作流程图解 ``` 原始据 → ODS(原始存储) ↓ ETL清洗 DWD(明细据) ↓ 维度关联 + 轻度汇总 DWS(宽表) ↓ 业务定制聚合 ADS(应用据) ↓ 服务接口/报表 最终应用 ``` #### 四、典型场景差异示例 1. **DWD 据** ```json { "order_id": "202311010001", "user_id": "u123", "item_id": "i456", "price": 299.00, "status": 2, "create_time": "2023-11-01 10:00:00" } ``` - 特点:保留原始交易明细,含未关联的 `user_id`/`item_id` 外键[^3] 2. **DWS 宽表** ```json { "user_id": "u123", "dt": "2023-11-01", "city": "北京", "age": 25, "total_order_amount": 1500.00, "daily_login_count": 3 } ``` - 特点:按用户-日期维度聚合,整合用户属性和行为指标[^1] 3. **ADS 据** ```json { "dt": "2023-11-01", "city": "北京", "age_group": "18-30", "gmv": 1200000.00, "active_user_count": 50000 } ``` - 特点:按城市-年龄段聚合,满足营销分析需求 --- ### 相关问题 1. **维度退化在 DWD 和 DWS 的实现有何不同?** - DWD 退化基础维度(如用户性别),DWS 退化复杂维度(如用户生命周期标签) 2. **宽表是否会导致存储膨胀?如何平衡性能与成本?** - 通过列式存储(Parquet/ORC)压缩 + 生命周期管理(自动清理旧分区)优化 3. **实时中 DWS 宽表如何实现?** - 使用 Flink 动态关联维表(如 HBase) + 窗口聚合生成实时宽表[^2] [^1]: 模型中各的职责定义与据加工逻辑 : 离线/实时架构中宽表的技术实现与优化策略 : 用户行为分析场景下的宽表构建与指标设计实践
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值