本文转载自微信公众号「大数据技术与数仓」,作者西贝。转载本文请联系大数据技术与数仓公众号。
写在前面
数据仓库(DataWarehouse)是一个面向主题的(SubjectOriented)、集成的(Integrated)、相对稳定的(Non-Volatile)、反映历史变化(TimeVariant)的数据集合,用于支持管理决策(DecisionMakingSupport)。近年来,随着大数据的应用不断深入,构建企业级数据仓库成为了企业进行精细化运营的一种趋势。
从管理者的视角来看,数据仓库是赋能业务并辅助决策的一种工具,从开发者的视角来看,数据仓库是一堆数据模型的集合。数仓开发是一个系统工程,涉及数据集成、数据建模、数据开发、数据服务、任务调度、元数据管理、数据质量管理(DQC)等一系列的流程。另外,由于数据跟业务是息息相关的,所以在构建数仓的时候,需要对业务有一个非常深刻的理解。
值得注意的是,数仓的建设不是一蹴而就的,也没有毕其功于一役的方法,业务的不断变化决定了数仓是在不断迭代中进行完善的。从这个层面上来讲,或许永远没有完美的数仓。由于人员的流动、业务的变化以及前期的系统性建设不足,数仓总会存在这样或那样的问题。
或许我们可以用"是否成熟"描述数仓的建设,那么什么是成熟的数仓呢,我们不妨换个角度思考一下:什么是一个不成熟的数据仓库?此时你的脑海里是否会蹦出一个词,那就是混乱。是的,一个不成熟的数仓虽然具备了部分数仓规范,但在具体的落地实施过程中,并未能完全按照规范操作,导致数据仓库建设比较混乱,比如数据域划分不清楚、数仓分层不明确、数据任务随意依赖、数据重复开发等等问题。迫于业务快速变化以及日常数据开发需求的压力,造成了数据开发没有太多的时间和精力去顾及这些问题,最终形成了一个不成熟的数仓。一旦出现了这些问题,后续就需要有专门的数据治理团队去规划并规范数仓的建设。
所以,假设你接手了一个不成熟的数仓项目,或者你觉得目前的数仓建设还不够成熟,那么不妨思考一下几个问题:
定目标
选技术
找问题
划主题
识分层
理建模
制规范
定目标数仓设计目标包括数仓分层清晰,字段与模型命名规范,具备较高可复用性与可维护性,能够快速响应产品运营层面的数据分析需求,以数据驱动产品迭代与业务增长。
数仓设计的过程中,坚持用户驱动与数据驱动相结合的设计理念,即一方面根据当前的业务数据的基础和质量情况,以数据源分析为出发点构建数据仓库;另一方面根据业务的方向性需求,从业务需要解决的具体问题出发,确定系统范围和需求框架。
选技术
数据仓库是一个复杂系统,会涉及到一系列的流程,由此不可避免的会使用很多的技术框架。目前,行业中使用的常见工具主要包括:数据同步工具、数据处理工具、任务调度工具、报表工具、元数据管理工具、质量管理平台(DQC)以及大数据基础平台等等。
如果是自建的大数据平台,或者是没有一个大数据开发平台,这种情况下需要数仓开发人员具备丰富的技术栈,既要兼顾技术的集成使用,又要兼顾数仓的建设与业务需求的开发。如果使用的是已经集成好的开发套件,比如阿里云的dataworks,这样数仓的开发人员会更加聚焦数仓的建设,而不是在各种技术的集成过程中踩坑而分散过多的精力。
找问题
前文已经提到没有完美的数仓,其实数仓的建设并没有对与错之分,只有好与坏之差。我们不能一味的使用拿来主义的方式去构建数据仓库,数据仓库建设能否成功会涉及很多的因素,数仓建设的方法论是指引我们的一个方向,万万不可迷失其中。一言以蔽之,合适就好。
在接手不成熟的数仓时,需要梳理存在的一些问题,而这些问题一般情况下都大同小异,常见的一些问题主要包括:
数仓分层不清晰
数据域划分不明确
模型设计不合理
代码不规范
命名不统一
划主题
主题域是业务过程的抽象集合,是在较高层次上对数据进行分类聚集的抽象,这是一个逻辑概念,主要方便数据的分类管理。业务过程就是企业经营过程中一个个不可拆分的行为事件,比如仓储管理里面有入库、出库、发货、签收,都是业务过程,抽象出来的主题域就是仓储域。主题域划分要尽量涵盖所有业务需求,保持相对稳定性,还具备一定的扩展性,新加入一个主题域,不影响已经划分的主题域的表。有了主题域之后,每个数据模型也就有了一个归属,这样数据组织会更加的清晰,同时也比较方便维护。
识分层
数仓为什么要分层
合理的数据仓库分层一方面能够降低耦合性,提高重用性,可读性可维护性,另一方面也能提高运算的效率,影响到数据需求迭代的速度,近而影响到产品决策的及时性。建立数据分层可以提炼公共层,避免烟囱式开发,可见一个合适且合理的数仓分层是极其重要。
通用分层设计思路
ODS:操作型数据(OperationalDataStore),指结构与源系统基本保持一致的增量或者全量数据。作为DW数据的一个数据准备区,同时又承担基础数据记录历史变化,之所以保留原始数据和线上原始数据保持一致,方便后期数据核对需要。
CDM:通用数据模型,又称为数据中间层(CommonDataModel),包含DWD、DWS、DIM层。
DWD:数据仓库明细层数据(DataWarehouseDetail)。对ODS层数据进行清洗转化,以业务过程作为建模驱动,基于每个具体的业务过程特点,构建最细粒度的明细事实表。可以结合企业的数据使用特点,基于维度建模思想,将明细事实表的某些重要属性字段做适当冗余,也即宽表化处理,构建明细宽表。
DWS:数据仓库汇总层数据(DataWarehouseSummary),基于指标需求,构建初步汇总事实表,一般是宽表。基于上层的应用和产品的指标需求,构建公共粒度的汇总指标表。以宽表化手段物理化模型,构建命名规范、口径一致的统计指标,为上层提供公共指标。
DIM:建立一致数据分析维表,可以降低数据计算口径不统一的风险,同时可以方便进行交叉探查。以维度作为建模驱动,基于每个维度的业务含义,通过添加维度属性、关联维度等定义计算逻辑,完成属性定义的过程并建立一致的数据分析维表。
ADS:面向应用的数据服务层(ApplicationDataService)。整合汇总成分析某一个主题域的服务数据,面向应用逻辑的数据加工。该层主要存放数据产品个性化的统计指标数据,这一层的数据直接对接数据的消费者,是产品、运营等角色可以直接感知理解的一层,大多数这一层的表都可以直接在BI上通过图表的形式直接透出。
分层辨析
ODS层
ODS层的概念主要体现在两个方面:
操作型系统的集成,用于当前、历史以及其它细节查询(业务系统的一部分)
为决策支持提供当前细节数据(数据仓库的一部分)
ODS是用于支持企业日常的全局应用的数据集合,ODS的数据具有面向主题、集成的、可变的以及数据是当前的或是接近当前的特点。同样也可以看出ODS是介于DB和DW之间的一种过渡存储。
值得注意的是,Kimball所说的ODS是物理落地关系型数据库中,但是在实际生产应用中,ODS往往是物理落地在数据仓库中,比如Hive。
通常来说ODS是在数据仓库中存储业务系统源数据,所以从数据粒度、数据结构、数据关系等各个方面都与业务系统的数据源保持一致。但是,也不能仅仅将ODS层看做是业务系统数据源的一个简单备份,ODS和业务系统数据源的差异主要是由于两者之间面向业务需求是不同的,业务系统是面向多并发读写同时有需要满足数据的一致性,而ODS数据通常是面向数据报表等批量数据查询需求。
关于ODS层与业务系统DB的主要区别,体现在一下几个方面:
数据存储方式方面。由于性能压力,业务DB需要对同一个逻辑表进行分表分库操作,而ODS会将业务系统中同一个逻辑表统一到一个物理实体中存储
数据存储介质方面。业务系统通常用oralce、MySQL、DB2等以事务性处理见长关系型数据库系统,ODS通常存储在以Hadoop为代表的分布式系统中,比如Hive等等。
数据组织形式方面。业务系统表通常需要遵循三范式,并且需要创建复杂的索引结构来提升查询效率,但是ODS层的表通常没有索引。
ODS层的数据同步通常会使用数据库直连抽取或者数据库日志抽取的方式,在设计ODS物理表时,在表命名、数据存储等方面都需要遵循一定的准则。比如:不管是表命名还是字段命名尽量和业务系统保持一致,但是需要通过额外的标识来区分增量和全量表,”_delta”来标识该表为增量表。另外,为了满足历史数据分析需求,我们需要在ODS表中加一个时间维度,这个维度通常在ODS表中作为分区字段。如果是增量存储,则可以按天为单位使用业务日期作为分区,每个分区存放日增量的业务数据。如果是全量存储,只可以按天为单位使用业务日期作为分区,每个分区存储截止到当前业务时间的全量快照数据。
DWD层
DWD层的数据一般存放明细事实表,为了提升访问便利性和访问性能,在维度模型的事实表基础上,将部分常用维度冗余到事实表,从而形成宽表模型。
明细事实表的设计有五个步骤:选择业务过程--->确定粒度--->选择维度--->确定事实(度量)--->冗余维度。
DWS层
以分析的主题对象作为建模驱动,基于上层的应用和产品的指标需求,构建公共粒度的汇总指标表。以宽表化手段物理化模型,构建命名规范、口径一致的统计指标,为上层提供公共指标,建立汇总宽表。如:形成日,周,月粒度汇总明细,或者基于某一个维度,如商品类目粒度的汇总日表,统计便于下一步报表数据结构的组织。
关于汇总层的表建模应遵循以下的原则:
数据公用性比如,汇总的聚集表能否与他人公用?基于某个维度的聚集是否是数据分析或者报表中经常使用的?如果满足这些情况,我们就有必要把明细数据沉淀到汇总表中。
不跨数据域数据域是在较高层次上对数据进行分类聚集的抽象,如交易统一划到交易域下,商品的新增、修改放到商品域下。
区分统计周期表命名上要能说明数据的统计周期,如_1d表示最近1天,_td截止到当天,_nd表示最近N天。
避免多个层级的数据应该避免将不同层级的数据放在一起,比如,如果存在7天和30天的事实,我们可以选择用两列存放7天和30天的事实,但是需要在列名和字段注释上说明清楚。同时我们也可以使用两张表分别存储不同统计周期的数据加以区分。
聚集是不跨越事实的聚集是针对原始星型模型进行的汇总,为了获取和查询原始模型一致的结果,聚集的维度和度量必须与原始模型保持一致,因此聚集是不跨事实的。横向钻取(交叉探查)是针对多个事实基于一致性维度进行的分析,很多时候采用融合事实表,预先存放横向钻取的结果,从而提高查询性能。因此融合事实表是一种导出模式而不是聚集。
DIM层
该层主要存储一致性维度数据,数据仓库总线架构重要基石之一就是一致性维度。通过构建一致性维度我们可以轻松实现数据的交叉探查。
维度是维度建模的基础和灵魂。维度建模中,将度量称为“事实”,将环境描述为“维度”,维度是用于分析事实所需要的多样环境。例如,在分析交易过程时,可以通过买家、卖家、商品和时间等维度描述交易发生的环境。维度所包含的表示维度的列,称为维度属性。维度属性是查询约束条件、分组和报表标签生成的基本来源,是数据易用性的关键。
ADS层
个性化指标加工,主要存储不具有公用性的复杂指标,比如针对某张数据报表设计的底层数据存储模型。
分层注意点
ODS不可以被应用层调用
CDM层任务的深度不宜过大
DWS优先调用DWD及DIM
避免ADS过渡引用明细层
理建模前文介绍了数据分层的概念,而数据建模更多的着眼于数据公共层处理。
好的数据建模有哪些特点
数据模型就是数据组织和存储方法,强调从业务、数据存储和数据使用角度合理存储数据。好的数据建模一般具备如下特点:
性能:能够帮助使用者快速查询所需要的数据,减少数据的I/O吞吐,提高使用数据的效率。
成本:减少不必要的数据冗余与重复计算,实现计算结果的良好复用,从而降低存储和计算成本。
质量:减少数据统计口径不一致性,减少数据计算错误的可能性。
数据模型设计原则
高内聚和低耦合一个逻辑和物理模型由哪些记录和字段组成,应该遵循最基本的软件设计方法论的高内聚和低耦合原则。主要从数据业务特性和访问特性两个角度来考虑:将业务相近或者相关的数据、粒度相同数据设计为一个逻辑或者物理模型;将高概率同时访问的数据放一起,将低概率同时访问的数据分开存储。
核心模型与扩展模型分离建立核心模型与扩展模型体系,核心模型包括的字段支持常用核心的业务,扩展模型包括的字段支持个性化或是少量应用的需要,不能让扩展字段过度侵入核心模型,破坏了核心模型的架构简洁性与可维护性。
公共处理逻辑下沉及单一越是底层公用的处理逻辑更应该在数据调度依赖的底层进行封装与实现,不要让公共的处理逻辑暴露给应用层实现,不要让公共逻辑在多处同时存在。
成本与性能平衡适当的数据冗余换取查询和刷新性能,不宜过度冗余与数据复制。
数据可回滚处理逻辑不变,在不同时间多次运行数据结果确定不变。
一致性相同的字段含义在不同表中字段命名必须相同,必须使用规范定义中的名称。
命名清晰可理解表命名需清晰、一致,表名需易于消费者理解和使用。
典型的数据仓库建模方法
数仓建模的典型方法有:实体建模(ER模型)、维度建模法、DataVault模型、Anchor模型。目前使用较多的当属维度建模,而维度建模中,又分为星型模型和雪花模型两大类,一般星型模型使用较多。
星型模型:维度建模非常直观,紧紧围绕着业务模型,可以直观的反映出业务模型中的业务问题。不需要经过复杂的表关联,就能够拿到业务分析想要的全部数据,能够极大的提升数据仓库的处理能力,缺点则是数据冗余较多。
雪花模型:在星型的基础上,分解维度,雪花模型的维度表可以拥有其他维度表的,虽然这种模型相比星型模型更规范一些,但是由于这种模型不太容易理解,维护成本比较高,而且性能方面需要关联多层维表,性能也比星型模型要低,普遍用的少一些。
关于维度建模,主要是将数据分为了维表和事实表。维度建模中,将度量称为“事实”,将环境描述为“维度”,维度是用于分析事实所需要的多样环境。例如,在分析交易过程时,可以通过买家、卖家、商品和时间等维度描述交易发生的环境。维度所包含的表示维度的列,称为维度属性。维度属性是查询约束条件、分组和报表标签生成的基本来源,是数据易用性的关键。
事实表
事实表作为数据仓库维度建模的核心,紧紧围绕着业务过程来设计,通过获取描述业务过程的度量来表达业务过程,包含了引用的维度和与业务过程有关的度量。事实表中一条记录所表达的业务细节程度被称为粒度。粒度通常可以通过两种方式来表述:一种是维度属性组合所表示的细节程度,一种是所表示的具体业务含义。
相对维度表来说,通常事实表要细长的多,行的增加速度也比维度表快很多。维度属性也可以存储到事实表中,这种存储到事实表中的维度列被称为退化维度。与其他存储在维度表中的维度一样,退化维度也可以用来作为事实表的过滤查询、实现聚合操作等。
事实表有三种类型:事务事实表、周期快照事实表、累积快照事实表。
维表
注意问题
尽可能包含丰富的维度属性丰富的维度属性可以为数据分析统计提供更多的分析角度
编码与文字描述共存尽可能多给出包括一些富有意义的文字性描述,除此之外,为了保持扩展性,需要将编码code与文字描述同时保留,方便以后新增加属性时导致错误的计算。比如商品维度中的商品ID和商品标题,类目ID和类目名称等。ID一般用于不同表之前的关联,而名称一般用于报表标签。
区分数值型的维度属性数值型字段是作为事实还是维度属性,取决于该字段的作用。如果通常是用于查询约束条件或分组统计,则是作为维度属性;如果通常是用于参与度量的计算,则是作为事实。比如商品价格,可以用于查询约束条件或统计价格区间的商品数量,此时是作为维度属性使用;也可以用于统计某类目下商品的平均价格,此时是作为事实使用。
尽量沉淀出通用的维度属性有些维度属性获取需要进行比较复杂的逻辑处理,有需要通过多表关联得到,也有单表的不同字段混合处理得到,或者对单表的某个字段进行解析得到。此时,需要将尽可能多的通用的维度属性进行沉淀。一方面,可以提高下游使用的方便性,减少复杂度;另一方面,避免下游使用解析时由于各自逻辑不同而导致的口径不一致。比如有些字段存储在JSON字符串中,则需要解析出来。再比如有时候无法直接获取某个维度属性,这个时候就需要进行加工判断,将其作为一个单独的属性字段。
维度表一般是很不规范化的。实际应用中,几乎总是使用维度表的空间来换取简明性和查询性能。
缓慢变化维
数据仓库的重要特点之一是反应历史变化,所以如何处理维度的变化是维度设计的重要工作之一。缓慢变化维的提出是因为在现实世界中,维度的属性并不是静态的,它会随着时间的变化而发生缓慢的变化,这一现象称为缓慢变化的维度,简称缓慢变化维。与数据增长较为快速的事实表相比,维度变化相对缓慢。
在Kimball的理论中,有三种缓慢变化的处理方式,分别是:
type1:重写维度值。采用此种方式,不保留历史,始终取最新数据。
type2:插入新的维度行。采用此种方式,保留历史,维度值变化前的事实和过去的维度值关联,维度值变化后的事实和当前的维度值关联。
type3:添加维度列
在Kimball的理论中,必须使用代理键作为每个维度表的主键,用于处理缓慢变化维度,这种方式在实际的操作中非常复杂,使用起来也不方便,所以一般情况下不使用代理键。
常用缓慢变化维的处理方式
常见的方式是使用快照来处理缓慢变化维。离线数仓按T+1计算,处理维度变化的方式就是每天一份全量快照。比如商品维度,每天保留一份全量商品快照数据。任意一天的事实均可以取到当天的商品信息,也可以取到最新的商品信息,通过限定日期,采用自然键进行关联即可。
此方式的优势是简单而有效,开发和维护成本低,另外使用方便,理解性好。数据使用方只需要限定日期即可取到当天的快照数据。任意一天的事实快照和任意一天的维度快照通过维度的自然键进行关联即可。主要的缺点就是会造成存储资源的浪费,由于存储成本远低于CPU、内存等成本,此方法总体来说弊大于利。
制规范
达成共识
对于数仓开发规范,务必要执行到位,确保大家能够达成一致的理解与认可。只有按照规范操作,才不至于使数仓最终变得越来越臃肿,越来越低效。关于规范的制定,需要经过团队人员的一致认可,具有可操作性,切不可畏手畏脚地被规范束缚,影响开发效率。
表命名规范
ODS层表命名规范比如全量表:ods.s{源系统表名}比如增量表:ods.s{源系统表名}_delta
DIM/DWD层表命名规范比如全量表:dwd_{数据域缩写}{自定义表命名}df比如增量表:dwd{数据域缩写}{自定义表命名}_di比如维表:dim[{业务域缩写}]{自定义表命名}
DWS层表命名规范dws_{数据域缩写}{维度缩写}{自定义表命名}{数字}_{d/m/y,分别表示天、月、年}
最近一天1d最近N天(N)d---N代表是一个数字最近30天1m最近7天1w最近365天1y周累计至今wtd----周报周(周六至周五)月初累计至今mtd累计至今td
ADS层表命名比如:ads_{数据域}{统计粒度}[{业务限定}][{自定义命名标签}]{统计周期}
关于表的命名需要根据具体团队的约定,一般见名知意即可,一旦规定了具体的格式,就尽量统一风格
开发规范
编码规范
SQL注释
总结
本文主要介绍了构建数仓的过程中或者在接手一个不成熟的数仓之后需要注意的一些问题,主要包括7个方面,分别是定目标、选技术、找问题、划主题、识分层、理建模、制规范。这些方面只是数仓构建中的一部分,由于篇幅限制,不能一一详述,希望本文对你有所帮助。