阿里云PAI-DeepRec CTR 模型性能优化天池大赛——获奖队伍技术分享
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了阿里云PAI-DeepRec CTR 模型性能优化天池大赛——获奖队伍技术分享相关的知识,希望对你有一定的参考价值。
阿里云联合英特尔举办的“创新大师杯”全球AI极客挑战赛——PAI-DeepRec CTR模型性能优化挑战赛已结束 ,此次大赛旨在DeepRec中沉淀CTR模型新的优化思路和优化方向。为了和大家共享经验成果,邀请获奖队伍分享解题思路,共同推动实际工业实际场景中点击率预估模型的训练效率的提升。
大家好,我们是MetaSpore团队,三位成员孙凯、苏程成、朱亚东均来自北京数元灵科技有限公司,其中苏程成就读于西安交大,曾为数元灵科技实习生。
今年7月中旬,阿里云联合 Intel 启动了“创新大师杯”全球AI极客挑战赛——PAI-DeepRec CTR模型性能优化,全球一共有超过3800支队伍报名参加比赛。经过近 5 个月的努力,我们在保障 6 个经典的 CTR 模型AUC 基本不损失的前提下,将训练效率提升了 3 倍以上,减少了接近 70% 的训练时间。团队在全球初赛和全球复赛都获得了排名第一的成绩,本文将就比赛中的整体思路和具体方案进行阐述。
解题思路
首先必须承认,这是一道比较难的题目。因为 DeepRec 已经集成了来自 Alibaba、Intel、Google等众多优秀工程师的智慧,在这个基础上再进行性能优化,不得不说是一个非常具有挑战性的问题。经过长时间的迭代,团队优化思路如下图所示,主要可以概括为一下 3 个方面:
- CTR稀疏模型训练优化:6个模型均为经典的 CTR 稀疏模型,在特征处理、算子等方面可能具有一定的优化空间。
- DeepRec训练加速参数调优:DeepRec 本身已经具有有来自 Alibaba 和 Intel 团队的很多优秀的技术沉淀,对模型训练有很多参数都可以进行调优。
- DeepRec框架性能优化:这个方面我们觉得可能在编译选项、优化器等方面有一定的空间,以便更好的发挥硬件潜能。
稀疏模型训练优化
- 选择更快的 GRUCell
对于DIEN模型,我们注意到其使用了GRU,而GRU是串行执行,必然会耗费大量时间,因此我们先把矛头对准了GRU。
阶段一:DIEN使用的是tf.nn.rnn_cell.GRUCell接口,在查阅 tensorflow 官方文档时我们注意到tf.contrib.rnn.GRUBlockCellV2能够有更好的性能。
因此我们将 tensorflow 中的tf.nn.rnn_cell.GRUCell改为了 tf.contrib.rnn.GRUBlockCellV2。tf.nn.rnn_cell.GRUCell是使用 python写的 GRU,因此其反向传播需要计算图层层传递。而tf.contrib.rnn.GRUBlockCellV2用 C++ 编写的,并且实现了 forward 和 backward,因此速度会相对快一点。
阶段二:在 GRU 的优化获得初步收益之后,我们在想能否有替代 GRU的网络结构。之后我们调研了替换 GRU 的方法,发现 SRU 可以在不损失 AUC 的情况下加快模型的训练,相比原始版本速度提升约80s。SRU 论文链接:
https://arxiv.org/pdf/1709.02755.pdf
为什么 SRU 会比较快呢?我们来看GRU与SRU的实现公式:
相比于GRU,SRU 对时序依赖更弱一些,SRU有 3 个步骤依赖于前面的状态,并且依赖 C(t-1) 的操作使用的是 Hadamard 积,计算量更小;论文最后还通过消融实验发现,与C(t-1)相关的 2 个操作可以省略,因此代码实现中并没有粉色部分。
阶段三(未采用):既然 GRU 能改成 SRU,那 SRU 能否继续优化呢,我们带着这个疑问开始尝试优化SRU,最终我们得到了一个保持 AUC 不变的简化版 SRU,其速度又能够提升 50s 左右。由于并没有严格的理论分析,最终我们并未把这个版本提交上去,不过在代码记录了这个版本。
- 优化稀疏特征表示
在查看DeepFM 模型的 Timeline 图(下图所示),我们发现其中有大量的 OneHot 算子异常耗时。
我们注意到官方文档中描述embedding_column 速度会更快,而且更适合高维稀疏的类别特征,于是我们将Indicator_column替换为了embedding_column。
对比结果如下:
训练加速参数调优
开启流水线在阅读 DeepRec 文档时,我们注意到了 AutoMicroBatch,它的本质是一个模型训练的流水线,多个MicroBatch 对梯度进行累加后更新至 variable,DeepRec 文档中给出的实测效果下图所示。
我们首先对这五个模型开启 micro_batch 进行了实验,发现Wide & Deep 模型不能使。我们首先对这五个模型开启micro_batch 进行了实验,发现Wide & Deep 模型不能使用 micro_batch,其使用的tf.feature_column.linear_model 接口与 micro_batch 冲突,导致运行crash,如下左图示。因此我们将 Wide & Deep 模型使用的 tf.feature_column.linear_model 进行了重写,如下右图所示。
经过了以上的准备,我们开启了micro_batch 的性能优化。1. 我们最初对所有模型都设置了相同的 micro_batch_num,经过我们实验,当micro_batch_num = 2时,所有模型都可达到 AUC 要求,相对原始版本速度可以提升900s左右。2. 当 micro_batch_num 再大一点,DIEN 模型的 AUC 会低于赛题标准,其他几个模型AUC基本没有变化。因此,我们对DIEN 模型进行了特殊处理,也就是给它单独设置一个 micro_batch_num ,最终经过我们实验,我们给DIEN模型 micro_batch_num 设置为 2,其他几个模型采用默认值 8。对比结果如下:
底层框架性能调优
- 优化编译选项
在DeepRec比赛教程中给出的编译选项如下
bazel build -c opt --cnotallow=opt --cnotallow=mkl_threadpool --define build_with_mkl_dnn_v1_notallow=true
该编译选项使用了针对intel处理器进行优化的 mkl_threadpool。tensorflow有很多可配置的编译选项,不同的编译选项会编译出不同性能的框架,经过我们尝试,在本次比赛中,经过优化编译选项,相较原始版本速度提升130s左右。
编译选项如下:
bazel build -c opt --cnotallow=opt //tensorflow/tools/pip_package:build_pip_package
对比结果如下:
2. 其他底层优化选项
下面是我们对于其他底层优化的想法与探索:
- 使用微软开源的 mimalloc 作为内存分配器可以进一步优化性能,实测可以节省 4% 的时间,但由于时间关系我们并未打包提交。
- MKL 库有比较多算子可供使用,可以针对不同的算子选择性地调用 MKL,这一方向也由于时间的关系没有来得及完成。
总结
在 DeepCTR 比赛中,我们从稀疏模型、训练加速调优、底层框架调优等 3 个方面出发,主要做了以上 5 点的优化,其中 GRU 算子和稀疏特征的优化灵感来自于团队之前在 MetaSpore 的开发中的技术沉淀。决赛阶段遇到了各路好手,很多问题的切入点独到而新颖,非常有启发性,值得我们学习和借鉴。
最后,将以上所有优化点进行叠加,我们得到如下总运行时间对比图,可以清晰的看到,经过我们的优化,模型训练效率得到 3 倍以上提升,训练时间减少了 70%。
注:以上测试都是在我们本地机器(8核16G)上进行的测试,因此与线上成绩有一定差异。
Github 链接:
https://github.com/meta-soul/DeepRec/tree/tianchi
DeepRec开源地址:
https://github.com/alibaba/DeepRec
构建与优化数据仓库·架构与模型设计--阿里云教程
点击关注上方“知了小巷”,
设为“置顶或星标”,第一时间送达干货。
构建与优化数据仓库·架构与模型设计--阿里云教程
技术架构选型
数仓分层
数据模型
层次调用规范
https://help.aliyun.com/document_detail/154238.html
技术架构选型
教程本身是以阿里云MaxCompute为例,实际上,流程和方法论是通用的。
在数据模型设计之前,您需要首先完成技术架构的选型。本教程中使用阿里云大数据产品MaxCompute配合DataWorks,完成整体的数据建模和研发流程
。
完整的技术架构图如下图所示。其中,DataWorks的数据集成负责完成数据的采集和基本的ETL【可以基于开源的相关技术组件构建数据采集和ETL基础平台】。MaxCompute作为整个大数据开发过程中的离线计算引擎。DataWorks则包括数据开发、数据质量、数据安全、数据管理等在内的一系列功能。
数仓分层
在阿里巴巴的数据体系中,我们建议将数据仓库分为三层,自下而上为:数据引入层(ODS,Operation Data Store)
、数据公共层(CDM,Common Data Model)
和数据应用层(ADS,Application Data Service)
。
数据仓库的分层和各层级用途如下图所示。
-
数据引入层ODS(Operation Data Store):存放未经过处理的原始数据至数据仓库系统,结构上与源系统保持一致,是 数据仓库的数据准备区
。主要完成基础数据引入到MaxCompute的职责,同时记录基础数据的历史变化。 -
数据公共层CDM(Common Data Model,又称通用数据模型层),包括 DIM维度表、DWD和DWS
,由ODS层数据加工而成。主要完成数据加工与整合,建立一致性的维度,构建可复用的面向分析和统计的明细事实表,以及汇总公共粒度的指标。
-
公共维度层(DIM):基于维度建模理念思想,建立整个企业的一致性维度。降低数据计算口径和算法不统一风险。公共维度层的表通常也被称为逻辑维度表,维度和维度逻辑表通常一一对应。
-
公共汇总粒度事实层(DWS):以分析的主题对象作为建模驱动,基于上层的应用和产品的指标需求,构建公共粒度的汇总指标事实表,以宽表化手段物理化模型。构建命名规范、口径一致的统计指标,为上层提供公共指标,建立汇总宽表、明细事实表。
公共汇总粒度事实层的表通常也被称为汇总逻辑表,用于存放派生指标数据。 -
明细粒度事实层(DWD):以业务过程作为建模驱动,基于每个具体的业务过程特点,构建最细粒度的明细层事实表。可以结合企业的数据使用特点,将明细事实表的某些重要维度属性字段做适当冗余,即宽表化处理。明细粒度事实层的表通常也被称为逻辑事实表。
-
数据应用层ADS(Application Data Service):存放数据产品个性化的统计指标数据。根据CDM与ODS层加工生成。
该数据分类架构在ODS层分为三部分:数据准备区、离线数据和准实时数据区
。整体数据分类架构如下图所示。
在本教程中,从交易数据系统的数据
经过DataWorks数据集成
,同步到数据仓库的ODS层
。经过数据开发形成事实宽表后,再以商品、地域等为维度进行公共汇总。
整体的数据流向如下图所示。其中,ODS层到DIM层的ETL(萃取(Extract)、转置(Transform)及加载(Load))处理是在MaxCompute中进行的,处理完成后会同步到所有存储系统。ODS层和DWD层会放在数据中间件中,供下游订阅使用。而DWS层和ADS层的数据通常会落地到在线存储系统中,下游通过接口调用的形式使用。
数据模型
1. 数据引入层(ODS)
ODS层存放您从业务系统获取的最原始的数据
,是其他上层数据的源数据。业务数据系统中的数据通常为非常细节的数据,经过长时间累积,且访问频率很高,是面向应用的数据
。
数据引入层表设计
本教程中,在ODS层主要包括的数据有:交易系统订单详情、用户信息详情、商品详情等。这些数据未经处理,是最原始的数据。逻辑上,这些数据都是以二维表
的形式存储。虽然严格的说ODS层不属于数仓建模的范畴,但是合理的规划ODS层并做好数据同步也非常重要。
本教程中,使用了6张ODS表:
记录用于拍卖的商品信息:s_auction。
记录用于正常售卖的商品信息:s_sale。
记录用户详细信息:s_users_extra。
记录新增的商品成交订单信息:s_biz_order_delta。
记录新增的物流订单信息:s_logistics_order_delta。
记录新增的支付订单信息:s_pay_order_delta。
说明:
通过_delta
来标识该表为增量表。
表中某些字段的名称刚好和关键字重名了,可以通过添加_col1
后缀解决。
建表示例(s_auction)
CREATE TABLE IF NOT EXISTS s_auction
(
id STRING COMMENT '商品ID',
title STRING COMMENT '商品名',
gmt_modified STRING COMMENT '商品最后修改日期',
price DOUBLE COMMENT '商品成交价格,单位元',
starts STRING COMMENT '商品上架时间',
minimum_bid DOUBLE COMMENT '拍卖商品起拍价,单位元',
duration STRING COMMENT '有效期,销售周期,单位天',
incrementnum DOUBLE COMMENT '拍卖价格的增价幅度',
city STRING COMMENT '商品所在城市',
prov STRING COMMENT '商品所在省份',
ends STRING COMMENT '销售结束时间',
quantity BIGINT COMMENT '数量',
stuff_status BIGINT COMMENT '商品新旧程度 0 全新 1 闲置 2 二手',
auction_status BIGINT COMMENT '商品状态 0 正常 1 用户删除 2 下架 3 从未上架',
cate_id BIGINT COMMENT '商品类目ID',
cate_name STRING COMMENT '商品类目名称',
commodity_id BIGINT COMMENT '品类ID',
commodity_name STRING COMMENT '品类名称',
umid STRING COMMENT '买家umid'
)
COMMENT '商品拍卖ODS'
PARTITIONED BY (ds STRING COMMENT '格式:YYYYMMDD')
LIFECYCLE 400;
数据引入层存储
为了满足历史数据分析需求
,您可以在ODS层表中添加时间维度作为分区字段。实际应用中,您可以选择采用增量
、全量
存储或拉链
存储的方式。
-
增量存储
以天为单位的增量存储,以业务日期作为分区,每个分区存放日增量的业务数据。举例如下:
1月1日,用户A访问了A公司电商店铺B,A公司电商日志产生一条记录t1。1月2日,用户A又访问了A公司电商店铺C,A公司电商日志产生一条记录t2。采用增量存储方式,t1将存储在1月1日这个分区中,t2将存储在1月2日这个分区中。
1月1日,用户A在A公司电商网购买了B商品,交易日志将生成一条记录t1。1月2日,用户A又将B商品退货
了,交易日志将更新t1记录。采用增量存储方式, 初始购买的t1记录将存储在1月1日这个分区中, 更新后的t1将存储在1月2日这个分区中。
交易、日志等
事务性较强的ODS表适合增量存储
方式。这类表数据量较大,采用全量存储的方式存储成本压力大。此外,这类表的下游应用对于历史全量数据访问的需求较小(此类需求可通过数据仓库后续汇总后得到)。例如,日志类ODS表没有数据更新的业务过程,因此所有增量分区UNION在一起就是一份全量数据。
-
全量存储
以天为单位的全量存储,以业务日期作为分区,每个分区存放截止到业务日期为止的全量业务数据
。
例如,1月1日,卖家A在A公司电商网发布了B、C两个商品,前端商品表将生成两条记录t1、t2。1月2日,卖家A将B商品下架
了,同时又发布了商品D,前端商品表将更新记录t1,同时新生成记录t3。采用全量存储方式, 在1月1日这个分区中存储t1和t2两条记录,在1月2日这个分区中存储更新后的t1以及t2、t3记录。
对于小数据量的缓慢变化维度数据,例如商品类目,可直接使用全量存储。
-
拉链存储 拉链存储通过 新增两个时间戳字段(start_dt和end_dt)
,将所有以天为粒度的变更数据都记录下来,通常分区字段也是这两个时间戳字段。
拉链存储举例如下。
这样,下游应用可以通过限制时间戳字段来获取历史数据。例如,用户访问1月1日数据,只需限制start_dt<=20160101并且 end_dt>20160101。
缓慢变化维度
MaxCompute不推荐使用代理键,推荐使用自然键作为维度主键,主要原因有两点:
-
MaxCompute是分布式计算引擎,生成全局唯一的代理键工作量非常大。当遇到大数据量情况下,这项工作就会更加复杂,且没有必要。 -
使用代理键会增加ETL的复杂性,从而增加ETL任务的开发和维护成本。
在不使用代理键的情况下,缓慢变化维度
可以通过快照
方式处理。
快照方式下数据的计算周期通常为每天一次。基于该周期,处理维度变化的方式为每天一份全量快照。
例如商品维度,每天保留一份全量商品快照数据。任意一天的事实表均可以取到当天的商品信息,也可以取到最新的商品信息,通过限定日期,采用自然键进行关联即可。该方式的优势主要有以下两点:
-
处理缓慢变化维度的方式简单有效,开发和维护成本低。 -
使用方便,易于理解。数据使用方只需要限定日期即可取到当天的快照数据。任意一天的事实快照与任意一天的维度快照通过维度的自然键进行关联即可。
该方法的弊端主要是存储空间的极大浪费
。例如某维度每天的变化量占总体数据量比例很低,极端情况下,每天无变化,这种情况下存储浪费严重。该方法主要实现了通过牺牲存储获取ETL效率的优化和逻辑上的简化。请避免过度使用该方法,且必须要有对应的数据生命周期制度,清除无用的历史数据
。
数据同步加载与处理
ODS的数据需要由各数据源系统同步到MaxCompute,才能用于进一步的数据开发。本教程建议您使用DataWorks
数据集成功能完成数据同步。在使用数据集成的过程中,建议您遵循以下规范:
-
一个系统的源表只允许同步到MaxCompute一次,保持表结构的一致性。 -
数据集成仅用于离线全量数据同步,实时增量数据同步需要您使用数据传输服务DTS实现,详情请参见数据传输服务DTS。 -
数据集成全量同步的数据直接进入全量表的当日分区。 -
ODS层的表建议以统计日期及时间分区表的方式存储,便于管理数据的存储成本和策略控制。 -
数据集成可以自适应处理源系统字段的变更: -
如果源系统字段的目标表在MaxCompute上不存在,可以由数据集成自动添加不存在的表字段。 -
如果目标表的字段在源系统不存在,数据集成填充NULL。
2. 公共维度汇总层(DIM)
公共维度汇总层(DIM)基于维度建模理念,建立整个企业的一致性维度。
公共维度汇总层(DIM)主要由维度表(维表)构成。维度是逻辑概念,是衡量和观察业务的角度。维表是根据维度及其属性将数据平台上构建的表物理化的表,采用宽表设计的原则。因此,构建公共维度汇总层(DIM)首先需要定义维度
。
定义维度
在划分数据域
、构建总线矩阵
时,需要结合对业务过程的分析定义维度
。以本教程中A电商公司的营销业务板块
为例,在交易数据域中,我们重点考察确认收货(交易成功)的业务过程。
在确认收货的业务过程中,主要有商品和收货地点(本教程中,假设收货和购买是同一个地点)两个维度所依赖的业务角度。
从商品角度可以定义出以下维度:
商品ID
商品名称
商品价格
商品新旧程度:0-全新、1-闲置、 2-二手
商品类目ID
商品类目名称
品类ID
品类名称
买家ID
商品状态:0-正常、1-用户删除、2-下架、3-从未上架
商品所在城市
商品所在省份
从地域角度,可以定义出以下维度:
买家ID
城市code
城市名称
省份code
省份名称
作为维度建模的核心,在企业级数据仓库中必须保证维度的唯一性。以A公司的商品维度为例,有且只允许有一种维度定义
。例如,省份code这个维度,对于任何业务过程所传达的信息都是一致的。
设计维表
完成维度定义后,您就可以对维度进行补充,进而生成维表了。
维表的设计需要注意:
-
建议维表 单表信息
不超过1000万条。 -
维表与其他表进行Join时,建议您 使用Map Join
。 -
避免过于频繁的更新
维表的数据。
在设计维表时,您需要从下列方面进行考虑:
-
维表中数据的稳定性。例如A公司电商会员通常不会出现消亡,但会员数据可能在任何时候更新,此时要考虑创建单个分区存储全量数据。如果存在不会更新的记录,您可能需要 分别创建历史表与日常表
。日常表用于存放当前有效的记录,保持表的数据量不会膨胀;历史表根据消亡时间插入对应分区,使用单个分区存放分区对应时间的消亡记录。 -
是否需要垂直拆分。如果一个维表存在大量属性不被使用,或由于承载过多属性字段导致查询变慢,则需考虑对字段进行拆分,创建多个维表。 -
是否需要水平拆分。如果记录之间有明显的界限,可以考虑拆成多个表或设计成多级分区。 -
核心的维表产出时间通常有严格的要求。
设计维表的主要步骤如下:
-
完成维度的初步定义,并保证维度的一致性。 -
确定主维表(中心事实表,本教程中采用 星型模型
)。此处的主维表通常是数据引入层(ODS)表,直接与业务系统同步。例如,s_auction是与前台商品中心系统同步的商品表,此表即是主维表。 -
确定相关维表。数据仓库是业务源系统的数据整合,不同业务系统或者同一业务系统中的表之间存在关联性。根据对业务的梳理,确定哪些表和主维表存在关联关系,并选择其中的某些表用于生成维度属性。以商品维度为例,根据对业务逻辑的梳理,可以得到商品与类目、卖家、店铺等维度存在关联关系。 -
确定维度属性,主要包括两个阶段。第一个阶段是从主维表中选择维度属性或生成新的维度属性;第二个阶段是从相关维表中选择维度属性或生成新的维度属性。以商品维度为例,从主维表(s_auction)和类目 、卖家、店铺等相关维表中选择维度属性或生成新的维度属性。
尽可能生成丰富的维度属性。
尽可能多地给出富有意义的文字性描述。
区分数值型属性和事实。
尽量沉淀出通用的维度属性。
公共维度汇总层(DIM)维表规范
公共维度汇总层(DIM)维表命名规范:dim_{业务板块名称/pub}_{维度定义}[_{自定义命名标签}]
,所谓pub是与具体业务板块无关或各个业务板块都可公用的维度,如时间维度。
举例如下:
公共区域维表dim_pub_area
A公司电商板块的商品全量表dim_asale_itm
建表示例
CREATE TABLE IF NOT EXISTS dim_asale_itm
(
item_id BIGINT COMMENT '商品ID',
item_title STRING COMMENT '商品名称',
item_price DOUBLE COMMENT '商品成交价格_元',
item_stuff_status BIGINT COMMENT '商品新旧程度_0全新1闲置2二手',
cate_id BIGINT COMMENT '商品类目ID',
cate_name STRING COMMENT '商品类目名称',
commodity_id BIGINT COMMENT '品类ID',
commodity_name STRING COMMENT '品类名称',
umid STRING COMMENT '买家ID',
item_status BIGINT COMMENT '商品状态_0正常1用户删除2下架3未上架',
city STRING COMMENT '商品所在城市',
prov STRING COMMENT '商品所在省份'
)
COMMENT '商品全量表'
PARTITIONED BY (ds STRING COMMENT '日期,yyyymmdd');
CREATE TABLE IF NOT EXISTS dim_pub_area
(
buyer_id STRING COMMENT '买家ID',
city_code STRING COMMENT '城市code',
city_name STRING COMMENT '城市名称',
prov_code STRING COMMENT '省份code',
prov_name STRING COMMENT '省份名称'
)
COMMENT '公共区域维表'
PARTITIONED BY (ds STRING COMMENT '日期分区,格式yyyymmdd')
LIFECYCLE 3600;
3. 明细粒度事实层(DWD)
明细粒度事实层以业务过程驱动建模,基于每个具体的业务过程特点,构建最细粒度的明细层事实表。您可以结合企业的数据使用特点,将明细事实表的某些重要维度属性字段做适当冗余,即宽表化处理
。
公共汇总粒度事实层(DWS)和明细粒度事实层(DWD)的事实表作为数据仓库维度建模的核心,需紧绕业务过程来设计。通过获取描述业务过程的度量来描述业务过程,包括引用的维度和与业务过程有关的度量。度量通常为数值型数据
,作为事实逻辑表的依据。事实逻辑表的描述信息是事实属性,事实属性中的外键字段通过对应维度进行关联。
事实表中一条记录所表达的业务细节程度被称为粒度。通常粒度可以通过两种方式来表述:一种是维度属性组合所表示的细节程度,一种是所表示的具体业务含义。
作为度量业务过程的事实,通常为整型或浮点型的十进制数值,有可加性、半可加性和不可加性三种类型:
-
可加性事实是指可以按照与事实表关联的任意维度进行汇总。 -
半可加性事实只能按照特定维度汇总,不能对所有维度汇总。例如库存可以按照地点和商品进行汇总,而按时间维度把一年中每个月的库存累加则毫无意义。 -
完全不可加性,例如比率型事实。对于不可加性的事实,可分解为可加的组件来实现聚集。
事实表相对维表通常更加细长,行增加速度也更快。维度属性可以存储到事实表中,这种存储到事实表中的维度列称为维度退化,可加快查询速度
。与其他存储在维表中的维度一样,维度退化可以用来进行事实表的过滤查询、实现聚合操作等。
明细粒度事实层(DWD)通常分为三种:事务事实表
、周期快照事实表
和累积快照事实表
,详情请参见数仓建设指南。
-
事务事实表用来描述业务过程,跟踪空间或时间上某点的度量事件,保存的是最原子的数据,也称为 原子事实表。 -
周期快照事实表以具有规律性的、可预见的时间间隔记录事实。 -
累积快照事实表用来表述过程开始和结束之间的关键步骤事件,覆盖过程的整个生命周期,通常具有多个日期字段来记录关键时间点。当累积快照事实表随着生命周期不断变化时,记录也会随着过程的变化而被修改。
明细粒度事实表设计原则
明细粒度事实表设计原则如下所示:
-
通常,一个明细粒度事实表仅和一个维度关联。 -
尽可能包含所有与业务过程相关的事实 。 -
只选择与业务过程相关的事实。 -
分解不可加性事实为可加的组件。 -
在选择维度和事实之前必须先声明粒度。 -
在同一个事实表中不能有多种不同粒度的事实。 -
事实的单位要保持一致。 -
谨慎处理Null值。 -
使用退化维度提高事实表的易用性。 -
明细粒度事实表整体设计流程如下图所示。
在一致性度量中已定义好了交易业务过程及其度量。明细事实表注意针对业务过程进行模型设计。明细事实表的设计可以分为四个步骤:选择业务过程
、确定粒度
、选择维度
、确定事实(度量)
。粒度主要是在维度未展开的情况下记录业务活动的语义描述。在您建设明细事实表时,需要选择基于现有的表进行明细层数据的开发,清楚所建表记录存储的是什么粒度的数据。
明细粒度事实层(DWD)规范
通常您需要遵照的命名规范为:dwd_{业务板块/pub}_{数据域缩写}_{业务过程缩写}[_{自定义表命名标签缩写}] _{单分区增量全量标识}
,pub表示数据包括多个业务板块的数据。单分区增量全量标识通常为:i表示增量,f表示全量。例如:dwd_asale_trd_ordcrt_trip_di(A电商公司航旅机票订单下单事实表,日刷新增量)及dwd_asale_itm_item_df(A电商商品快照事实表,日刷新全量)。
本教程中,DWD层主要由三个表构成:
交易商品信息事实表:dwd_asale_trd_itm_di。
交易会员信息事实表:ods_asale_trd_mbr_di。
交易订单信息事实表:dwd_asale_trd_ord_di。
建表示例(dwd_asale_trd_itm_di)
CREATE TABLE IF NOT EXISTS dwd_asale_trd_itm_di
(
item_id BIGINT COMMENT '商品ID',
item_title STRING COMMENT '商品名称',
item_price DOUBLE COMMENT '商品价格',
item_stuff_status BIGINT COMMENT '商品新旧程度_0全新1闲置2二手',
item_prov STRING COMMENT '商品省份',
item_city STRING COMMENT '商品城市',
cate_id BIGINT COMMENT '商品类目ID',
cate_name STRING COMMENT '商品类目名称',
commodity_id BIGINT COMMENT '品类ID',
commodity_name STRING COMMENT '品类名称',
buyer_id BIGINT COMMENT '买家ID',
)
COMMENT '交易商品信息事实表'
PARTITIONED BY (ds STRING COMMENT '日期')
LIFECYCLE 400;
4. 公共汇总粒度事实层(DWS)
明细粒度 ==> 汇总粒度
公共汇总粒度事实层以分析的主题对象作为建模驱动
,基于上层的应用和产品的指标需求构建公共粒度的汇总指标事实表。公共汇总层的一个表通常会对应一个派生指标。
公共汇总事实表设计原则
聚集是指针对原始明细粒度的数据
进行汇总。DWS公共汇总层是面向分析对象的主题聚集建模。在本教程中,最终的分析目标为:最近一天某个类目(例如:厨具)商品在各省的销售总额、该类目Top10销售额商品名称、各省用户购买力分布。因此,我们可以以最终交易成功
的商品、类目、买家等角度对最近一天的数据进行汇总。
聚集是不跨越事实的。聚集是针对原始星形模型进行的汇总。为获取和查询与原始模型一致的结果,聚集的维度和度量必须与原始模型保持一致,因此聚集是不跨越事实的。 聚集会带来查询性能的提升,但聚集也会增加ETL维护的难度。当子类目对应的一级类目发生变更时,先前存在的、已经被汇总到聚集表中的数据需要被重新调整。
此外,进行DWS层设计时还需遵循以下原则:
-
数据公用性: 需考虑汇总的聚集是否可以提供给第三方使用。您可以判断,基于某个维度的聚集是否经常用于数据分析中。如果答案是肯定的,就有必要把明细数据经过汇总沉淀到聚集表中。 -
不跨数据域: 数据域是在较高层次上对数据进行分类聚集的抽象。数据域通常以业务过程进行分类,例如交易统一划到交易域下,商品的新增、修改放到商品域下。 -
区分统计周期: 在表的命名上要能说明数据的统计周期,例如 _1d
表示最近1天
,td表示截至当天
,nd表示最近N天
。
公共汇总事实表规范
公共汇总事实表命名规范:dws_{业务板块缩写/pub}_{数据域缩写}_{数据粒度缩写}[_{自定义表命名标签缩写}]_{统计时间周期范围缩写}
。关于统计实际周期范围缩写,缺省情况下,离线计算应该包括最近一天(_1d)
,最近N天(_nd)
和历史截至当天(_td)
三个表。如果出现_nd的表字段过多需要拆分时,只允许以一个统计周期单元作为原子拆分。即一个统计周期拆分一个表,例如最近7天(_1w)拆分一个表。不允许拆分出来的一个表存储多个统计周期。
对于小时表
(无论是天刷新还是小时刷新),都用_hh
来表示。对于分钟表
(无论是天刷新还是小时刷新),都用_mm
来表示。
举例如下:dws_asale_trd_byr_subpay_1d
(A电商公司买家粒度交易分阶段付款一日汇总事实表)
dws_asale_trd_byr_subpay_td(A电商公司买家粒度分阶段付款截至当日汇总表)
dws_asale_trd_byr_cod_nd(A电商公司买家粒度货到付款交易汇总事实表)
dws_asale_itm_slr_td(A电商公司卖家粒度商品截至当日存量汇总表)
dws_asale_itm_slr_hh(A电商公司卖家粒度商品小时汇总表)---维度为小时
dws_asale_itm_slr_mm(A电商公司卖家粒度商品分钟汇总表)---维度为分钟
建表示例
满足业务需求的DWS层建表语句如下
CREATE TABLE IF NOT EXISTS dws_asale_trd_byr_ord_1d
(
buyer_id BIGINT COMMENT '买家ID',
buyer_nick STRING COMMENT '买家昵称',
mord_prov STRING COMMENT '收货人省份',
cate_id BIGINT COMMENT '商品类目ID',
cate_name STRING COMMENT '商品类目名称',
confirm_paid_amt_sum_1d DOUBLE COMMENT '最近一天订单已经确认收货的金额总和'
)
COMMENT '买家粒度所有交易最近一天汇总事实表'
PARTITIONED BY (ds STRING COMMENT '分区字段YYYYMMDD')
LIFECYCLE 36000;
CREATE TABLE IF NOT EXISTS dws_asale_trd_itm_ord_1d
(
item_id BIGINT COMMENT '商品ID',
item_title STRING COMMENT '商品名称',
cate_id BIGINT COMMENT '商品类目ID',
cate_name STRING COMMENT '商品类目名称',
mord_prov STRING COMMENT '收货人省份',
confirm_paid_amt_sum_1d DOUBLE COMMENT '最近一天订单已经确认收货的金额总和'
)
COMMENT '商品粒度交易最近一天汇总事实表'
PARTITIONED BY (ds STRING COMMENT '分区字段YYYYMMDD')
LIFECYCLE 36000;
层次调用规范
在完成数据仓库的分层后,您需要对各层次的数据之间的调用关系作出约定。
ADS应用层优先调用数据仓库公共层数据。如果已经存在CDM层数据,不允许ADS应用层跨过CDM中间层从ODS层重复加工数据
。CDM中间层应该积极了解应用层数据的建设需求,将公用的数据沉淀到公共层,为其他数据层次提供数据服务。同时,ADS应用层也需积极配合CDM中间层进行持续的数据公共建设的改造。避免出现过度的ODS层引用、不合理的数据复制和子集合冗余。总体遵循的层次调用原则如下:
-
ODS层数据不能直接被应用层任务引用。如果中间层没有沉淀的ODS层数据,则通过CDM层的视图访问。CDM层视图必须使用调度程序进行封装,保持视图的 可维护性与可管理性。 -
CDM层任务的深度不宜过大(建议不超过10层)。 -
一个计算刷新任务只允许一个输出表,特殊情况除外。 -
如果多个任务刷新输出一个表(不同任务插入不同的分区),DataWorks上需要建立一个虚拟任务,依赖多个任务的刷新和输出。通常,下游应该依赖此虚拟任务。 -
CDM汇总层优先调用CDM明细层,可累加指标计算。CDM汇总层尽量优先调用已经产出的粗粒度汇总层,避免大量汇总层数据直接从海量的明细数据层中计算得出。 -
CDM明细层累计快照事实表优先调用CDM事务型事实表,保持数据的一致性产出。 -
有针对性地建设CDM公共汇总层,避免应用层过度引用和依赖CDM层明细数据。
猜你喜欢
点一下,代码无 Bug
以上是关于阿里云PAI-DeepRec CTR 模型性能优化天池大赛——获奖队伍技术分享的主要内容,如果未能解决你的问题,请参考以下文章
深入云原生 AI:基于 Alluxio 数据缓存的大规模深度学习训练性能优化
深入云原生 AI:基于 Alluxio 数据缓存的大规模深度学习训练性能优化