离线数仓(九)【DWS 层开发】(2)

本文涉及的产品
云原生数据仓库AnalyticDB MySQL版,基础版 8ACU 100GB 1个月
简介: 离线数仓(九)【DWS 层开发】

离线数仓(九)【DWS 层开发】(1)https://developer.aliyun.com/article/1532432

V3.0

       其实,我们还可以进一步进行优化(把两个粒度统一为一个粒度:用户-商品粒度),因为我们 ADS 最终要求的粒度是 品牌和品类粒度,所以我们的数据从 DWD 到 DWS 层同样的数据需要聚合两次得到统计粒度分别为 用户-品牌和用户-品类 的这么两类数据,然后 ADS 层再对两张表分别进行过滤。

       我们这里可以做一个优化:把用户-品牌和用户-品类这两个粒度统一为用户-商品粒度(粒度变得更细),等 ADS 层需要调用的时候再分别过滤,这样我们在 DWD 层到 DWS 层的过程就可以省去大量的计算开销。

CREATE EXTERNAL TABLE dws_trade_user_sku_order_1d
(
    `user_id`                    STRING COMMENT '用户id',
    `sku_id`                   STRING COMMENT '商品id',
    `brand_name`                 STRING COMMENT '品牌名称',
    `order_count`                BIGINT COMMENT '下单次数',
    `order_num`                  BIGINT COMMENT '下单件数',
    `order_amount`               DECIMAL(16,2) COMMENT '下单金额'
) COMMENT '交易域用户商品粒度订单最近1日汇总事实表'
    PARTITIONED BY (`dt` STRING)
    STORED AS ORC
    LOCATION '/warehouse/gmall/dws/dws_trade_brand_order_1d'
    TBLPROPERTIES ('orc.compress' = 'snappy');
 
CREATE EXTERNAL TABLE dws_trade_user_brand_order_nd
(
    `user_id`                    STRING COMMENT '用户id',
    `sku_id`                   STRING COMMENT '商品id',
    `brand_name`                 STRING COMMENT '品牌名称',
    `order_count_7d`                BIGINT COMMENT '下单次数',
    `order_num_7d`                  BIGINT COMMENT '下单件数',
    `order_amount_7d`               DECIMAL(16,2) COMMENT '最近7天的下单金额',
    `order_count_30d`                BIGINT COMMENT '下单次数',
    `order_num_30d`                  BIGINT COMMENT '下单件数',
    `order_amount_30d`               DECIMAL(16,2) COMMENT '最近30天的下单金额'
) COMMENT '交易域品牌粒度订单最近7/30日汇总事实表'
    PARTITIONED BY (`dt` STRING)
    STORED AS ORC
    LOCATION '/warehouse/gmall/dws/dws_trade_brand_order_1d'
    TBLPROPERTIES ('orc.compress' = 'snappy');

装载语句这里就省略了,只不过就是 group by 的字段改成了 user_id和sku_id。

这样,我们最终的派生指标分类就可以分为两类了,最终根据统计周期只需要建 4 张表即可:

1.0.5、历史至今的汇总表

create external table dws_trade_user_order_td
(
    `user_id`                    STRING COMMENT '用户id',
    `order_date_first`           STRING COMMENT '首次下单日期',
    `order_date_last`           STRING COMMENT '最近一次下单日期',
    `order_count`                BIGINT COMMENT '下单次数',
    `order_num`                  BIGINT COMMENT '下单件数',
    `order_total_amount`         DECIMAL(16,2) COMMENT '历史下单总额'
)comment '交易域用户粒度历史至今订单汇总事实表'
partitioned by (`dt` STRING)
stored as orc
location '/warehouse/gmall/dws/dws_trade_user_order_td'
tblproperties ('orc.compress' = 'snappy');

装载数据(区分首日和每日)

-- 数据装载
-- 2020-06-14
insert overwrite table dws_trade_user_order_td partition(dt='2020-06-14')
select
    user_id,
       min(date_id),
       max(date_id),
       count(distinct (order_id)),
       sum(sku_num),
       sum(split_total_amount)
from dwd_trade_order_detail_inc
group by user_id;
-- 2020-06-15
insert overwrite table dws_trade_user_order_td partition(dt='2020-06-15')
select
    user_id,
       min(order_date_first),
       max(order_date_last),
       sum(order_count),
       sum(order_num),
       sum(order_total_amount)
from
(
        select
        user_id,
           order_date_first,
           order_date_last,
           order_count,
           order_num,
           order_total_amount
    from dws_trade_user_order_td
    where dt=date_sub('2020-06-15',1)
    union all
    select
            user_id,
           '2020-06-15',
           '2020-06-15',
           count(distinct(order_id)) order_count_1d,
           sum(sku_num) order_num_1d,
           sum(split_total_amount) order_total_amount_1d
    from dwd_trade_order_detail_inc
    where dt='2020-06-15'
    group by user_id
)t1
group by user_id;

1.0.6、DWS 层设计总结

(1)1d 表

表结构:行由派生指标的统计粒度决定,列由统计粒度id和派生指标决定。

分区:按天分区,每天存放的是当天明细的汇总结果。

数据装载:找到 DWD 层与之对应的明细表,从明细表拿一个分区的数据进行汇总,汇总之后放到汇总表的当天分区。

(2)nd 表

表结构:行和列和 1d 表基本一致,无非就是把派生指标分为 7d 和 30d。

分区:按天分区,每天存放的是截止当前最近n天的汇总结果。

数据装载:优先去 DWS 层的 1d 表中去取数据,直接拿30个分区的数据进行聚合(聚合时用sum(if)把7d的数据和30d的数据区分开来,聚合之后放到汇总表的当天分区。

(3)td 表

表结构:行和列还是分别根据粒度和派生指标决定。

分区:按天分区,每天存放的是历史截止当前的汇总结果。

数据装载:首日需要从 DWS 层的 1d 表中或者 DWD 中的明细表中获取数据。第二天之后从 td 表中拿到前一个分区的数据,然后再从 1d 表或者 DWD 中的明细表找到今天的汇总结果,然后把这两部分数据进行 union all 得到截止今天的汇总结果。

1.1、最近1日汇总表

1.1.1、 交易域用户商品粒度订单最近1日汇总表

建表语句
DROP TABLE IF EXISTS dws_trade_user_sku_order_1d;
CREATE EXTERNAL TABLE dws_trade_user_sku_order_1d
(
    `user_id`                   STRING COMMENT '用户id',
    `sku_id`                    STRING COMMENT 'sku_id',
    `sku_name`                  STRING COMMENT 'sku名称',
    `category1_id`              STRING COMMENT '一级分类id',
    `category1_name`            STRING COMMENT '一级分类名称',
    `category2_id`              STRING COMMENT '一级分类id',
    `category2_name`            STRING COMMENT '一级分类名称',
    `category3_id`              STRING COMMENT '一级分类id',
    `category3_name`            STRING COMMENT '一级分类名称',
    `tm_id`                     STRING COMMENT '品牌id',
    `tm_name`                   STRING COMMENT '品牌名称',
    `order_count_1d`            BIGINT COMMENT '最近1日下单次数',
    `order_num_1d`              BIGINT COMMENT '最近1日下单件数',
    `order_original_amount_1d`  DECIMAL(16, 2) COMMENT '最近1日下单原始金额',
    `activity_reduce_amount_1d` DECIMAL(16, 2) COMMENT '最近1日活动优惠金额',
    `coupon_reduce_amount_1d`   DECIMAL(16, 2) COMMENT '最近1日优惠券优惠金额',
    `order_total_amount_1d`     DECIMAL(16, 2) COMMENT '最近1日下单最终金额'
) COMMENT '交易域用户商品粒度订单最近1日汇总事实表'
    PARTITIONED BY (`dt` STRING)
    STORED AS ORC
    LOCATION '/warehouse/gmall/dws/dws_trade_user_sku_order_1d'
    TBLPROPERTIES ('orc.compress' = 'snappy');

       这张表可以大概分为两部分:维度字段和度量字段。其中度量字段中的统计粒度是必须的,退化字段是为了方便我们后期使用添加的(也可以不添加),而度量字段除了 ADS 层要求的,我们这里也“前瞻性”地添加了一些度量指标,防止后期该表麻烦,而且添加几个字对计算开销没什么影响,毕竟一张表里的聚合函数只会取一次数据。

       分区我们按天分区,每天存储的内容都是当天的汇总结果。

数据装载(区分首日/每日装载)

       因为我们在首日装载的时候有大量的历史数据(从属于不同的分区),所以我们要动态分区来装载。

首日装载

       我们在建表的时候退化了很多商品维度的字段,所以我们在装载数据的时候就应该把这部分数据通过 sku_id join 到一起,而我们 dwd 中存在大量历史的数据,所以用 14 号的商品信息去关联历史上的下单记录很可能对应不上,所以我们需要判断 null。

       我们在搭建数仓的时候,历史的订单数据(事实)是有的,但是历史的商品信息(维度)是没有的,所以我们这里只能用首日的商品信息去关联历史的下单信息。

set hive.exec.dynamic.partition.mode=nonstrict;
insert overwrite table dws_trade_user_sku_order_1d partition(dt)
select
    user_id,
    id,
    sku_name,
    category1_id,
    category1_name,
    category2_id,
    category2_name,
    category3_id,
    category3_name,
    tm_id,
    tm_name,
    order_count_1d,
    order_num_1d,
    order_original_amount_1d,
    activity_reduce_amount_1d,
    coupon_reduce_amount_1d,
    order_total_amount_1d,
    dt
from
(
    select
        dt,
        user_id,
        sku_id,
        count(*) order_count_1d,
        sum(sku_num) order_num_1d,
        sum(split_original_amount) order_original_amount_1d,
        sum(nvl(split_activity_amount,0.0)) activity_reduce_amount_1d,
        sum(nvl(split_coupon_amount,0.0)) coupon_reduce_amount_1d,
        sum(split_total_amount) order_total_amount_1d
    from dwd_trade_order_detail_inc
    group by dt,user_id,sku_id
)od
left join
(
    select
        id,
        sku_name,
        category1_id,
        category1_name,
        category2_id,
        category2_name,
        category3_id,
        category3_name,
        tm_id,
        tm_name
    from dim_sku_full
    where dt='2020-06-14'
)sku
on od.sku_id=sku.id;

每日装载

insert overwrite table dws_trade_user_sku_order_1d partition(dt='2020-06-15')
select
    user_id,
    id,
    sku_name,
    category1_id,
    category1_name,
    category2_id,
    category2_name,
    category3_id,
    category3_name,
    tm_id,
    tm_name,
    order_count,
    order_num,
    order_original_amount,
    activity_reduce_amount,
    coupon_reduce_amount,
    order_total_amount
from
(
    select
        user_id,
        sku_id,
        count(*) order_count,
        sum(sku_num) order_num,
        sum(split_original_amount) order_original_amount,
        sum(nvl(split_activity_amount,0)) activity_reduce_amount,
        sum(nvl(split_coupon_amount,0)) coupon_reduce_amount,
        sum(split_total_amount) order_total_amount
    from dwd_trade_order_detail_inc
    where dt='2020-06-15'
    group by user_id,sku_id
)od
left join
(
    select
        id,
        sku_name,
        category1_id,
        category1_name,
        category2_id,
        category2_name,
        category3_id,
        category3_name,
        tm_id,
        tm_name
    from dim_sku_full
    where dt='2020-06-15'
)sku
on od.sku_id=sku.id;

离线数仓(九)【DWS 层开发】(3)https://developer.aliyun.com/article/1532437

相关实践学习
AnalyticDB MySQL海量数据秒级分析体验
快速上手AnalyticDB MySQL,玩转SQL开发等功能!本教程介绍如何在AnalyticDB MySQL中,一键加载内置数据集,并基于自动生成的查询脚本,运行复杂查询语句,秒级生成查询结果。
阿里云云原生数据仓库AnalyticDB MySQL版 使用教程
云原生数据仓库AnalyticDB MySQL版是一种支持高并发低延时查询的新一代云原生数据仓库,高度兼容MySQL协议以及SQL:92、SQL:99、SQL:2003标准,可以对海量数据进行即时的多维分析透视和业务探索,快速构建企业云上数据仓库。 了解产品 https://www.aliyun.com/product/ApsaraDB/ads
相关文章
|
5月前
|
存储 数据采集 JavaScript
深入理解数仓开发(一)数据技术篇之日志采集
深入理解数仓开发(一)数据技术篇之日志采集
|
5月前
|
消息中间件 关系型数据库 Kafka
深入理解数仓开发(二)数据技术篇之数据同步
深入理解数仓开发(二)数据技术篇之数据同步
|
3月前
|
消息中间件 监控 关系型数据库
Serverless 应用的监控与调试问题之实时离线数仓一体化常用的解决方案有什么问题
Serverless 应用的监控与调试问题之实时离线数仓一体化常用的解决方案有什么问题
|
4月前
|
存储 DataWorks Java
DataWorks产品使用合集之开发离线数仓时,需要多个工作空间的情况有哪些
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
5月前
|
消息中间件 存储 Kafka
Flink 实时数仓(二)【ODS 层开发】
Flink 实时数仓(二)【ODS 层开发】
|
5月前
|
存储 消息中间件 NoSQL
Flink 实时数仓(一)【实时数仓&离线数仓对比】(2)
Flink 实时数仓(一)【实时数仓&离线数仓对比】
|
1月前
|
人工智能 自然语言处理 关系型数据库
阿里云云原生数据仓库 AnalyticDB PostgreSQL 版已完成和开源LLMOps平台Dify官方集成
近日,阿里云云原生数据仓库 AnalyticDB PostgreSQL 版已完成和开源LLMOps平台Dify官方集成。
|
1月前
|
人工智能 分布式计算 数据管理
阿里云位居 IDC MarketScape 中国实时湖仓评估领导者类别
国际数据公司( IDC )首次发布了《IDC MarketScape: 中国实时湖仓市场 2024 年厂商评估》,阿里云在首次报告发布即位居领导者类别。
|
1月前
|
SQL 分布式计算 数据挖掘
加速数据分析:阿里云Hologres在实时数仓中的应用实践
【10月更文挑战第9天】随着大数据技术的发展,企业对于数据处理和分析的需求日益增长。特别是在面对海量数据时,如何快速、准确地进行数据查询和分析成为了关键问题。阿里云Hologres作为一个高性能的实时交互式分析服务,为解决这些问题提供了强大的支持。本文将深入探讨Hologres的特点及其在实时数仓中的应用,并通过具体的代码示例来展示其实际应用。
155 0
|
2月前
|
存储 机器学习/深度学习 监控
阿里云 Hologres OLAP 解决方案评测
随着大数据时代的到来,企业面临着海量数据的挑战,如何高效地进行数据分析和决策变得尤为重要。阿里云推出的 Hologres OLAP(在线分析处理)解决方案,旨在为用户提供快速、高效的数据分析能力。本文将深入探讨 Hologres OLAP 的特点、优势以及应用场景,并针对方案的技术细节、部署指导、代码示例和数据分析需求进行评测。
127 7