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

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

前言

       上一个 DWD 层用了半个月时间,但是慢有慢的好处;今天开始 DWS 层的学习,目标是 4 月初把项目完成,完了赶紧从头回顾一遍项目。

       今天操场跑了 20 分钟,顺便在这里记录一下,现在每周只有没早八的时候能跑一下了,近一年没有好好跑步了,这个习惯应该找回来了。

1、DWS 层开发

       DWS 也叫数据汇总层,它的职责就是把一些计算耗时的公共中间结果提前保存起来(比如提前 join  两张表),用空间换时间!所以 DWS 层是依托于需求的(需求驱动),没有需求我们是不知道需要保存哪些中间结果的。

1.0、DWS 层设计

1.0.1、设计要点

(1)DWS层的设计参考指标体系(原子、派生、衍生指标等)。一般能通过一张明细事实表聚合得到的,那就是派生指标;得不到就是衍生指标。

(2)DWS层的数据存储格式为ORC列式存储 + snappy压缩。

(3)DWS层表名的命名规范为dws_数据域_统计粒度_业务过程_统计周期(1d/nd/td),这里的统计粒度可以是多个

注:1d表示最近1日,nd表示最近n日,td表示历史至今。

       我们接下来的汇总表的设计并不会把 1d、nd、td 这三个字段都放到一张表里,比如对于页面浏览这个业务过程,如果我们把三个字段都放到一张表里,那么当装载数据的时候,它需要从 DWD 的当天分区、前n天分区、历史分区中拿数据,这样的代价太大了,而如果我们把三个字段分开,一天的汇总结果放到一天的分区,当够了n天的时候,我们直接从 DWS 同层的 1d 中拿7天的就够了,而且 1d 的表已经帮我们聚合好了。尽管我们在学习 DWD 层的时候希望同层的表不要有依赖关系,但是在这里是可以的。

       而且我们并不会按照统计周期去创建n张表,而是只创建两张表:统计周期为1的和统计周期为n的。

1.0.2、构建指标体系

下面我们根据 ADS 层商品域的交易主题下的需求来进行指标分析:

       这里的度量值为 1 ,意思是我们并没有专门的维度供我们计算(度量值和维度的界限并不是那么清晰,并不是说度量值就非得是什么金额、下单件数等),我们的一行数据就代表一个度量值(这里指一个订单)。

1.0.3、抽取派生指标

       我们需要列出所有需求的指标类型,然后从一堆需求中找到其中业务过程、统计粒度、统计周期相同的派生指标放到一张汇总表里。一般我们会把所有需求对应的派生指标都放到一张表里去分析:

       比如上面的表格是我们把所有交易域的需求对应的派生指标放到了一起,可以看到,我们需要创建4张汇总表,但是考虑到不同的统计周期,我们这里需要创建 8 张汇总表。

       首先至少得 3 个字段:品牌id,下单次数、下单人数。考虑到 ADS 层需要展示更详细的数据比如品牌名称,如果我们这里不加的话到时候还得用 DWS 层的表去和 DIM 层的维度表去 join 才能得到。所以我们这里尽量也做一个维度退化。毕竟我们分层的时候,DIM 层是同时跨越 DWD 和 DWS 层的:

关于分区,对于 1d 的汇总结果,它的当日分区放的就是当日的明细汇总结果。

1.0.4、最近1d和nd的汇总表

       我们的下单次数和下单人数这两个派生指标是可以放到一张汇总表的:

CREATE EXTERNAL TABLE dws_trade_brand_order_1d
(
    `brand_id`                   STRING COMMENT '品牌id',
    `brand_name`                 STRING COMMENT '品牌名称',
    `order_count`                STRING COMMENT '下单次数',
    `order_user_count`                STRING COMMENT '下单人数'
) COMMENT '交易域品牌粒度订单最近1日汇总事实表'
    PARTITIONED BY (`dt` STRING)
    STORED AS ORC
    LOCATION '/warehouse/gmall/dws/dws_trade_brand_order_1d'
    TBLPROPERTIES ('orc.compress' = 'snappy');

       这张表显然十分简单,但是考虑到我们数仓的需求并不是一成不变的,比如现在增加两个需求:统计最近1/7/30日各品牌的下单件数、下单金额。显然这两个指标也都是派生指标,而且它们的业务过程(下单)、统计粒度(品牌)和统计周期(1/7/30)和我们这张表都是一样的,所以我们就需要修改这张表结构,但是修改表就意味着我们需要处理这张表原本的历史数据,显然十分麻烦。所以我们在最初建表的时候就应该尽可能避免将来的改表操作,为此,我们提供了两种方案:

       1. 之前我们把所有业务过程、统计粒度和统计周期相同的派生指标会都放到一个汇总表里,现在我们可以为每个派生指标建一张汇总表,这样即使有新的派生指标加进来也不用担心对旧表的影响,但是这样我们的 DWS 层会出现大量的表,所以我们一般并不采用。

       2. 我们可以“前瞻性”地把这张事实表(比如下单的事实表就是 order_detail)的度量值去预测将来可能用到的派生指标:

CREATE EXTERNAL TABLE dws_trade_brand_order_1d
(
    `brand_id`                   STRING COMMENT '品牌id',
    `brand_name`                 STRING COMMENT '品牌名称',
    `order_count`                BIGINT COMMENT '下单次数',
    `order_user_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');

这张表的数据装载也很简单:

insert overwrite table dws_trade_brand_order_1d partition (dt='2020-06-14')
select tm_id,
       tm_name,
       count(*),
       count(distinct user_id),
       sum(sku_num),
       sum(split_total_amount)
from
(
     select
        sku_id,
        user_id,
        sku_num,
        split_total_amount
    from dwd_trade_order_detail_inc
    where dt='2020-06-14'
)od
left join
(
    select
        id,
        tm_id,
        tm_name
    from dim_sku_full
    where dt='2020-06-14'
)sku
on od.sku_id=sku.id
group by tm_id,tm_name;

       关于下单的 1d 的汇总表已经设计完毕了,解下来就是 nd 汇总表的设计了。对于 nd ,它每天的分区里放的就是这一天最近 n 天的数据。

CREATE EXTERNAL TABLE dws_trade_brand_order_nd
(
    `brand_id`                   STRING COMMENT '品牌id',
    `brand_name`                 STRING COMMENT '品牌名称',
    `order_count_7d`                BIGINT COMMENT '下单次数',
    `order_user_count_7d`           BIGINT COMMENT '下单人数',
    `order_num_7d`                  BIGINT COMMENT '下单件数',
    `order_amount_7d`               DECIMAL(16,2) COMMENT '最近7天的下单金额',
    `order_count_30d`                BIGINT COMMENT '下单次数',
    `order_user_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');

       关于 nd 表的数据从哪取?我们一般都是直接从它的 1d 表去拿的,如果实在不行(比如我们的需求中并没有 1d 的需求)那我们只能去 DWD 去拿了。

数据装载:我们只需要分别查询出 7d 和 30d 的数据直接 join 即可:

insert overwrite table dws_trade_brand_order_nd partition (dt='2020-06-14')
select xxxx
from
(
-- 7d
select
    brand_id,
    brand_name,
    sum(order_count),
    sum(order_user_count),
    sum(order_num),
    sum(order_amount)
from dws_trade_brand_order_1d
where dt>=date_sub('2020-06-14',6)
group by brand_id,brand_name
) d7
join
(
--30d
select
    brand_id,
    brand_name,
    sum(order_count),
    sum(order_user_count),
    sum(order_num),
    sum(order_amount)
from dws_trade_brand_order_1d
where dt>=date_sub('2020-06-14',29)
group by brand_id,brand_name
)d30
on d7.sku_id=d30.sku_id

这里,因为前 30 天的数据包含了前 7 天的数据,所以我们可以对这个 SQL 进行一个优化:

insert overwrite table dws_trade_brand_order_nd partition (dt='2020-06-14')
select
    brand_id,
    brand_name,
    sum(`if`(dt>=date_sub('2020-06-14',6),order_count,0)),
    sum(`if`(dt>=date_sub('2020-06-14',6),order_user_count,0)),
    sum(`if`(dt>=date_sub('2020-06-14',6),order_num,0)),
    sum(`if`(dt>=date_sub('2020-06-14',6),order_amount,0)),
    sum(order_count),
    sum(order_user_count),
    sum(order_num),
    sum(order_amount)
from dws_trade_brand_order_1d
where dt>=date_sub('2020-06-14',29)
group by brand_id,brand_name;

       这样我们就不用专门去查询近 7 天的数据,而且还少 join 了一次。但是这张表存在一个问题,我们之前在 1d 表中计算下单人数的时候对用户是去了重的,因为一个用户一天可能下单多次;按道理 7d 30d 同样需要对相同的用户进行去重,因为一个用户可能在多天中下单,所以我们这里需要解决这个同一用户重复计算的问题。

V2.0

我们可以通过改变这张表的粒度(改为用户品牌和用户品类粒度)来解决这个问题:

既然粒度已经是用户品牌粒度,那指标下单人数就不需要了,只需要在查询的时候直接去重即可。

CREATE EXTERNAL TABLE dws_trade_user_brand_order_1d
(
    `user_id`                    STRING COMMENT '用户id',
    `brand_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_user_brand_order_1d'
    TBLPROPERTIES ('orc.compress' = 'snappy');

装载语句只需要稍微改改即可:

insert overwrite table dws_trade_user_brand_order_1d partition (dt='2020-06-14')
select
       user_id,
       tm_id,
       tm_name,
       count(*),
       sum(sku_num),
       sum(split_total_amount)
from
(
     select
        sku_id,
        user_id,
        sku_num,
        split_total_amount
    from dwd_trade_order_detail_inc
    where dt='2020-06-14'
)od
left join
(
    select
        id,
        tm_id,
        tm_name
    from dim_sku_full
    where dt='2020-06-14'
)sku
on od.sku_id=sku.id
group by user_id,tm_id,tm_name;

修改 nd 表的建表语句:

CREATE EXTERNAL TABLE dws_trade_user_brand_order_nd
(
    `user_id`                    STRING COMMENT '用户id',
    `brand_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');

修改 nd 表的装载语句:

insert overwrite table dws_trade_user_brand_order_nd partition (dt='2020-06-14')
select
    user_id,
    brand_id,
    brand_name,
    sum(`if`(dt>=date_sub('2020-06-14',6),order_count,0)),
    sum(`if`(dt>=date_sub('2020-06-14',6),order_num,0)),
    sum(`if`(dt>=date_sub('2020-06-14',6),order_amount,0)),
    sum(order_count),
    sum(order_num),
    sum(order_amount)
from dws_trade_user_brand_order_nd
where dt>=date_sub('2020-06-14',29)
group by brand_id,brand_name;

现在,我们的指标(各品牌的下单件数和下单人数) 就变成了:

最终我们的派生指标根据统计粒度分为两类:

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

相关实践学习
阿里云云原生数据仓库AnalyticDB MySQL版 使用教程
云原生数据仓库AnalyticDB MySQL版是一种支持高并发低延时查询的新一代云原生数据仓库,高度兼容MySQL协议以及SQL:92、SQL:99、SQL:2003标准,可以对海量数据进行即时的多维分析透视和业务探索,快速构建企业云上数据仓库。 了解产品 https://www.aliyun.com/product/ApsaraDB/ads
相关文章
|
3月前
|
人工智能 OLAP 数据处理
解锁数仓内AI流水线,AnalyticDB Ray基于多模ETL+ML提效开发与运维
AnalyticDB Ray 是AnalyticDB MySQL 推出的全托管Ray服务,基于开源 Ray 的丰富生态,经过多模态处理、具身智能、搜索推荐、金融风控等场景的锤炼,对Ray内核和服务能力进行了全栈增强。
|
6月前
|
分布式计算 运维 监控
Dataphin离线数仓搭建深度测评:数据工程师的实战视角
作为一名金融行业数据工程师,我参与了阿里云Dataphin智能研发版的评测。通过《离线数仓搭建》实践,体验了其在数据治理中的核心能力。Dataphin在环境搭建、管道开发和任务管理上显著提效,如测试环境搭建从3天缩短至2小时,复杂表映射效率提升50%。产品支持全链路治理、智能提效和架构兼容,帮助企业降低40%建设成本,缩短60%需求响应周期。建议加强行业模板库和移动适配功能,进一步提升使用体验。
|
2月前
|
关系型数据库 OLAP 数据库
免费试用|Vibe Coding正当时,AnalyticDB Supabase极速开发爆款应用
云原生数据仓库AnalyticDB PostgreSQL版重磅推出Supabase托管版本
|
7月前
|
SQL 运维 BI
湖仓分析|浙江霖梓基于 Doris + Paimon 打造实时/离线一体化湖仓架构
浙江霖梓早期基于 Apache Doris 进行整体架构与表结构的重构,并基于湖仓一体和查询加速展开深度探索与实践,打造了 Doris + Paimon 的实时/离线一体化湖仓架构,实现查询提速 30 倍、资源成本节省 67% 等显著成效。
338 3
湖仓分析|浙江霖梓基于 Doris + Paimon 打造实时/离线一体化湖仓架构
|
存储 DataWorks Java
DataWorks产品使用合集之开发离线数仓时,需要多个工作空间的情况有哪些
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
消息中间件 监控 关系型数据库
Serverless 应用的监控与调试问题之实时离线数仓一体化常用的解决方案有什么问题
Serverless 应用的监控与调试问题之实时离线数仓一体化常用的解决方案有什么问题
|
3月前
|
分布式计算 运维 监控
Fusion 引擎赋能:流利说如何用阿里云 Serverless Spark 实现数仓计算加速
本文介绍了流利说与阿里云合作,利用EMR Serverless Spark优化数据处理的全过程。流利说是科技驱动的教育公司,通过AI技术提升用户英语水平。原有架构存在资源管理、成本和性能等痛点,采用EMR Serverless Spark后,实现弹性资源管理、按需计费及性能优化。方案涵盖数据采集、存储、计算到查询的完整能力,支持多种接入方式与高效调度。迁移后任务耗时减少40%,失败率降低80%,成本下降30%。未来将深化合作,探索更多行业解决方案。
160 1
|
4月前
|
SQL 关系型数据库 MySQL
客户说|保险极客引入阿里云AnalyticDB,多业务场景效率大幅提升
“通过引入AnalyticDB,我们在复杂数据查询和实时同步方面取得了显著突破,其分布式、弹性与云计算的优势得以充分体现,帮助企业快速响应业务变化,实现降本增效。AnalyticDB的卓越表现保障了保险极客数据服务的品质和效率。”
|
7月前
|
存储 分布式计算 物联网
美的楼宇科技基于阿里云 EMR Serverless Spark 构建 LakeHouse 湖仓数据平台
美的楼宇科技基于阿里云 EMR Serverless Spark 建设 IoT 数据平台,实现了数据与 AI 技术的有效融合,解决了美的楼宇科技设备数据量庞大且持续增长、数据半结构化、数据价值缺乏深度挖掘的痛点问题。并结合 EMR Serverless StarRocks 搭建了 Lakehouse 平台,最终实现不同场景下整体性能提升50%以上,同时综合成本下降30%。
574 58