大家好,我是老兵。
过了年,小伙伴们又开始了新一轮内卷
。我也没闲着,假期抽空整理了企业级数仓建设
方案。
整体内容包括:
数仓架构
数仓分层规划
数据流向规划
数据同步策略
数仓命名规范
通篇内容紧贴企业级建设主题,参考了一些数仓架构师的数仓建设方法论
和企业落地
实践方案,希望大家耐心看完。
ODS层
: 贴源层。旨在集团、子公司、互联网及三方外部数据输入层,基本保持源表原貌(存在敏感数据加密)。
DW层
: 数仓层。可细分为dwd和dws子层。
DWD层
为数据明细层。依据数仓模型对ODS数据整合形成数据明细,同时常与DIM层交互进行维度建模。
DWS层
为数据汇总层。依据DWD层明细数据按需轻度汇总,例如:按页面汇总访问日志;按接入口统计PV/UV、按天统计访问流量等。
DIM层
。维度层,保存一些企业常用的维度表,如: 日期维、地区维、商品维、用户维等。
DM层
: 数据集市层(主题层)。面向应用主题汇总DW层数据(如: 渠道、产品、会员等主题)。此层更加偏向业务,维度多样化、覆盖更全面
APP层
: 面向具体应用的结果集,包含但不限于:集团共享库、子公司的分析私库、输出接口库等
企业级数仓体系的建设是一个循环上升
的过程,在项目初期需要进行合理梳理和清晰定义,其具体建设将结合项目实施分阶段
、分步骤
的逐步完善。
企业级数仓数据分层的原则和特点如下:
功能定位明确
:数据层的定位应清晰,即每层的功能和用途需要保证明确单一,避免由于设计上的交叉重复导致混乱和低效,造成后续维护困难。
层次衔接紧密、完整
: 数据层次间的功能衔接必须紧凑,且各数据层的功能集合汇总应覆盖整个企业数据体系的全部既定数据服务功能。
专有的模型策略、存储周期
。由于各数据层的功能定位不同,其对应的数据组织(模型设计策略)也各不相同。因此需为各数据层制定适合的模型设计策略和存储周期。
2.1.1 功能定位
贴源层为其他数据层提供数据加载
和转换
的数据源,是数据的临时准备区。收录包括集团的各业务系统数据、子公司数据、各类外部购买数据及补录数据等手动数据源。
贴源层的数据能够支撑数据处理容错所需的数据追溯
要求。
保留原始数据,历史可追溯
在数据加工处理过程中,可能会出现采集数据源异常、或者加载异常,这时分析和解决问题往往需要对数据源进行回溯查询加载,因此贴源层的数据将起到支撑源数据查询分析和追溯
的作用。
同时屏蔽系统的数据结构差异化
。各个源系统的数据结构不同,通过贴源层屏蔽数据结构的差异,保证基础层向上供数的一致性。
2.1.2 模型设计原则
贴源层存储的数据在模型上采取贴源设计。即偏向于维持源系统数据组织的原貌形态
。
在贴源层,数据模型设计方案基本不会考虑对源数据信息的删减,保持与源系统数据相同的
数据结构。
有时可能会因业务使用需求或一些技术、空间、安全等因素,比如: 贴源层敏感加密
信息字段等,但基本上会保留所有业务信息性相关的字段。
贴源层内部表加工原则: 内部的表加工,在表加工时,贴源层内部表不存在表间依赖关系
。
2.1.3 存储周期
贴源层进行原貌数据历史存储。因此从原则上来说,源数据在数据集市中无需冗余存储
,只需存储当前数据(重跑机制)。
为支持加载脚本重跑机制的容错
和数据追溯
需求,数据加载需对应具体的脚本策略。
最终的数据存储,一般选择分区形式进行数据加载,实现历史数据的保存(按照时间分区)。
2.2.1 功能定位
DWD层数据基于企业标准进行统一的加工整合,包括数据清洗、异常值、维度建模
等过程,最终面向各个业务系统的不同业务需求提供一致
、规范
的明细数据。
DWS层的建设采取应用中性
的设计原则,即基础层的建设并不偏向于某应用,而是按照逻辑主题划分并集中存储来源于各业务系统的数据。按需进行轻度汇总
,构建企业级的数据视图,支持各类分析型应用。
2.2.2 模型设计原则
应用中性的原则
根据对源系统的分析调研结果,并结合数据标准项目的成果进行客户化后,最终形成具有中性特征的基础层数据模型。
该数据模型涵盖整个相关业务范围,且满足不断产生的业务发展需求,结合了业务角度建模
方法和关系建模
方法。
能够强烈表示业务规则,明确实体间各种可能的限制条件和关系。比如父子关系
、排它分类
、多对多
等。
模型设计体现高度的结构化、模块化设计思想。在主体域体现主要分类、实体间关系、历史信息的保存等,体现了一个清晰、严谨的模型架构。
模型的一致性
整个数仓层的逻辑数据模型必须在设计过程中保持统一的业务定义,比如渠道的定义、客户的分类等。
所有的业务指标应该在整个企业内部保持一致,使得后续数据应用系统在使用同一数据信息时获取统一的、规范的数据内容。
粒度最细原则
DWD明细层是汇总层的数据来源,为了支持各子公司的各类应用,建议保留最明细粒度的数据。
DWD层
保留最细粒度的明细数据
,DWS层
在逻辑通用的原则下,按需进行轻度汇总
。
历史数据存储原则
按需来存储历史数据,包括按日、按月分区历史明细数据存储;少量维度表和事实表全量存储、拉链存储等。
2.2.3 数据存储周期
数仓层的数据是数仓架构中最基础、最细节的数据,是DM集市层
和APP应用层
的数据来源。因此在数仓层中的数据存储周期策略非常重要,关系着整个数据集市的数据支撑能力。数仓层的数据保存周期策略主要来自于如下方面的需求驱动:
集团的业务特点
集团内有些数据表的业务周期较长
,因此对数据的历史追溯性有较高要求。考虑保障业务持续性,需要设计足够长的数据存储和保留周期。
其他部门业务分析需求
为了满足子公司或其他业务部门的数据集市需求,需提供业务统计和报表分析需求,一般都需要指定长度
的历史数据。例如: 支持计算xx的年日均余额,则需要本年度到当日的至少12个月前的历史数据。
2.3.1 功能定位
数据集市层是从业务的视角出发,提炼出具有共性
的数据查询、历史统计需求,从而构建一个面向支持应用的、共享的数据访问服务的公共数据层。
集市层的建设从技术角度来看,具有如下功能:
1) 降低数据冗余、重复计算和不一致
DM层会同时服务于不同应用,实现数据和指标共享。因此需减少相同的业务系统所带来的数据重复计算
和存储
,且避免数据在多次加工后出现的不一致
情况。
2)加快数据查询效率
由于DW数仓层数据和业务指标经过整合计算存储在DM集市层。在一定程度上,减少了频繁对DW层数据表关联和数据计算所带来的性能问题,从而整体降低了系统总开销
并加快了单个查询的响应时间。
3)减弱应用开发、数据查询的复杂度
DM集市层从业务分析的视角组织数据,屏蔽了数据仓库的复杂性,便于前端应用的开发。
我们再来看看从业务层面来看DM集市层的构建,具有哪些功能?
1) 快速落实业务指标
DM数据集市层基于业务分析指标中的定义,对业务统计口径
进行统一
的数据加工和维护,实现业务分析指标在数据集市中的快速落地。
2)加快应用的加工进度
实现数据与统计口径的共享,降低了应用加工和使用数据的复杂度,因此可以减少应用开发中相当一部分的重复工作,提高工作效率。
3)便于业务人员使用
数据集市层中的表可看作是对业务的逻辑描述,业务人员可直接使用数据进行查询分析。数据集市层的建立完善了一个便于业务人员理解的数据视图,可以供其直接使用。
4)多层次的数据访问服务体系
助力提升数据集市的价值,集市层和数仓层中的数据各有侧重,共同提供了面向特定分析的应用层。
面向业务人员的即席数据查询,以及面向应用开发者的应用访问接口,通过建立一套多层次的数据访问体系
,以满足不同类型应用的需要。
2.3.2 模型设计原则
1)宽表设计
某种程度上对该层宽表采用维度建模的方法。首先根据业务需要尽量包含更多的属性(维度)和指标,同时也要考虑空间限制。集市层模型设计的处理策略通常主要为如下三种:
预连接。即将原来分散在DW数仓层中的很多实体根据应用的要求进行预连接,减少查询访问的开销。
预计算。即将在DW数仓层中或者APP应用层中不易计算(规则复杂、计算时间长),比如日均、重定价日等,进行预计算,降低计算复杂度,结果保持粒度不变(最细粒度)。
预聚合。即以维度建模
方式对DW数仓层数据进行汇总和聚合。
2) 数据组织
集市层在数据的组织上,偏重于业务语义的体现。将数据信息抽象性弱化,业务含义的表达更加直接。
例如:某账户的开户日期,在DW数仓层
的表达为"合同的开始日期",而在DM数据集市
层则直接表达为"账户的开户日期",对业务人员来讲,这种表达方式更加容易理解与接受。
3) 数据粒度
集市层的数据包含多种数据粒度。需要根据业务主题和汇总粒度的不同进行逐层加工统计和汇总。
4) 基于应用需求建设
集市层的建设路径,应结合数据仓库&数据集市需求分析结果和业界的实施经验,并在统计口径等角度参考和遵从企业数据标准
的相关规范。
从适合的汇总层次和数据信息出发,逐步完善并推广DM集市层的建设和使用。
5) 内部表加工原则
根据表的依赖关系
加工:先加工细粒度的汇总表,后加工大粗粒度的加工表。例如:先加工客户粒度的表,再加工子公司粒度的表。
2.3.3 数据存储周期
集市层数据表的存储周期,主要考虑因素为业务需求和当前空间的可用性。
逻辑上,数据集市层的数据都是从数据集市层的细粒度数据加工汇总而得到的,该过程可重复回溯
,因此集市层的历史数据保留并不是必须的。
但是考虑到重新产生集市层数据的时间开销很大,因此也常常从快速响应应用及业务需求
的角度,对集市层数据进行部分保留。
2.4.1 功能定位
应用层是针对特定主题域
、部门
或用户
而建设的数据集合,直接支持在数据集市之上的应用。
应用层中的数据一般仅面向于特定应用
、按需定制
即可。包含各中心的固定报表、指标分析、数据多维分析等。应用层可以分为报表区、接口区、标签区等部分。
2.4.2 模型设计原则
1) 应用层数据的组织没有固定方式,一般为星型
为主,其数据来源包括DW数仓层和集市层。
2) 数据组织应尽量避免冗余
,保证最大限度的利用集市层的数据,尽量存放其他层没有的指标或服务的专有数据。
3) 应用层的表根据实际业务需求
加工,可以存在依赖关系。
2.4.3 数据存储周期
应用层完全为定制化的应用提供数据服务,需满足线上多维分析或固定报表的长久使用,一般建议数据长期存储
。
应用层可根据实际情况需要确定数据存储周期。在制定数据存储周期策略时,应充分考虑到其下层(DW数层层、DM集市层)历史数据资源情况,减少对数据的冗余存储。
DW数据仓库和DM集市内部的数据流向必须是单向的,通俗理解就是:同一份数据,只可以按照数仓体系固有的从低到高的顺序进行加工,具体的数据流向约束如下:
ODS贴源
层的数据可以作为DW数仓
层的来源,DM数据集市层
不能直接用贴源层的数据。
DW数仓
层的数据可以作为DM集市
层和APP应用
层的数据来源。(APP应用层最好直接从DM集市获取)。
DM集市
层的数据可以作为APP应用层
的数据来源。
不允许除上述情形外的其他数据加工流向。
整体数据架构中除ODS贴源层
外的每层都可以向外部应用提供数据访问服务。因此,外部对每个数据层的访问流向是基本不受限的,但访问时仍注意按照"应用层->集市层->数仓层"的优先顺序。
通俗理解可以参考如下规则:
如果访问的数据已在应用层按照特定需求加工完成,则应该直接取应用层的数据。
若数据未在应用层中进行定制加工,则可以考虑其是否为比较共性的业务需求,是否可以从集市层直接获取或根据集市简单加工而得。
否则考虑从数仓层数据中获取;除非特殊情况,数据集市不推荐从贴源层直接获取业务数据。
数据同步过程按照供数的方式可以分为全量
和增量
两种形式。按照存储的话又可分为覆盖
、交易
、快照
和拉链
等四种形式。
其中,根据数据量大小,可以粗略的制定分层内数据同步加载策略(下图仅示例):
1) 全量
全量
是从源表中抽取数据的方式之一,每次同步源表的所有数据进行后续处理。
2) 增量
增量
是从源表中抽取数据的方式之一。首次抽取时(初始化
)全量抽取,之后每次只同步变更
的数据。
3) 覆盖
覆盖
是指将数据存放到目标表时的一种同步方式。通过该方式存放数据时,每次先清除
目标表中的所有数据,然后将要加载到目标表的数据全部插入
到目标表中,即用最新的
数据覆盖原来的旧数据。
一般和全量同步一起使用。
4) 交易
交易
是指将数据保存到目标表数据的另一种同步方式。每次将最新的
数据插入到目标表中。适用于源表数据不会发生修改,值会随着时间增加
的表。
5) 快照
快照
是指在目标表中添加一个数据的快照时间标识
的字段,用于区分数据何时加载。为了介绍方便,后面简称为数据加载时间。
每次加载数据时,根据ETL程序的运行时间作为这一批次数据的加载时间,这样不同时间、不同批次的数据,目标表的数据加载时间也不同。
一般和全量同步
配合使用,这样每一批数据的加载时间相同的数据,相当于目标表在该时间的一张照片,根据数据加载时间作为区分,将目标表历史上不同时间的不同版本
都保存下来。
6) 拉链
拉链
同步也称为历史拉链。通过该方式同步数据,仅当存放到目标表中的数据发生变更
时,对应的记录才会发生变动。
通过目标表中记录的开始时间
和结束时间
来记录数据的历史变化轨迹。这样就能有效保留历史数据的变动信息,也不会浪费存储空间。
1) 拉链表应用场景
拉链表包含记录开始时间
(from_dt)、记录结束时间
(to_dt)、加载日期
(load_dt)和记录状态
(status),用以标识记录的变化过程。
比如:在2021-07-01 12:21:21
时向该表中新添一条记录A,如下表。
id | from_dt | to_dt | load_dt | status |
---|---|---|---|---|
A | 2021-07-01 12:21:21 | 9999-12-31 23:59:59 | 2021-07-01 12:21:21 | I |
在 2021-07-02 10:01:01
时由于记录A发生了变化。
因此我们对原有记录的结束时间和开始时间作出修改,并新增一条记录,如下表:
id | from_dt | to_dt | load_dt | status |
---|---|---|---|---|
A | 2021-07-01 12:21:21 | 2021-07-02 10:01:01 | 2021-07-01 12:21:21 | D |
A | 2021-07-02 10:01:01 | 9999-12-31 23:59:59 | 2021-07-02 10:01:01 | I |
在上表中我们可以看出:
加载日期
(load_dt)表示记录被插入到表中的时间
记录开始时间
(from_dt)和记录结束时间
(to_dt)是用来表示记录在哪段时间范围内是有效的。
记录状态
(status)则表示该记录目前处理哪种状态:I(新增)、U(更新)和D(删除)。
from_dt(开始时间) <= data_dt(指定时间) <= to_dt(结束时间)。
在获取当前有效记录时,除通过指定时间判断外,还可以通过status(状态)来判断: status <> 'D'
2) 快照表应用场景
在快照表包含记录统计日期
(stat_dt)、数据加载时间
(load_dt),用来标识记录的变化过程。
如: 在2021-07-01 12:21:21
时向该表中新添一条记录A,如下表。
id | stat_dt | load_dt |
---|---|---|
A | 2021-06-30 12:21:21 | 2021-07-01 12:21:21 |
在 2021-07-12 12:21:21
时由于记录A发生了变化。
id | stat_dt | load_dt |
---|---|---|
A | 2021-06-30 12:21:21 | 2021-07-01 12:21:21 |
A | 2021-07-10 12:21:21 | 2021-07-12 12:21:21 |
从上面表格看到:
数据加载日期
(load_dt)表示记录被插入到表中的时间
统计日期
(stat_dt)是表示记录的内容和状态是在哪个时间点下的,相当于在统计日期(stat_dt)的时间点为这条记录拍了一张照片,记录了这条记录的所有信息。
在使用时,我们通过统计日期(stat_dt)来获取指定时间(data_dt)的有效记录。
统计日期(stat_dt) <= 指定日期(data_dt)
在满足上面条件的记录中取统计日期
(stat_dt)最大记录,即为指定日期(data_dt)下的有效记录。
如果获取当前最新日期,直接获取统计日期(stat_dt)最大的记录即可。
3) 交易表应用场景
交易表中一般存放的是流水
记录,不存在修改记录和删除记录信息的情况,所以只需要将新增
的记录插入到表中即可。
使用的时候,交易表就是一张普通的全量表,里面包含每个流水的信息。直接根据检索条件查询即可。
4) 全量覆盖表应用场景
全量覆盖表一般是指数据集市中的表所对应的表存放的记录已经包含的历史信息。所以只需要将表中所有记录
都导入进来,保持同步数据集市中的表。
这种表的使用根据表中存放历史记录
的形式,来确认获取很有效记录的方式。
根据数据架构分为下列层次,命名规范为:
层级 | 命名缩写 |
---|---|
贴源层 | ODS |
数仓层-明细层 | DWD |
数仓层-汇总层 | DWS |
集市层&主题层 | DM |
应用层 | APP |
主题 | 命名 | 备注 |
---|---|---|
客户 | CUS | 客户基本信息、资产、联系地址、标签、会员、商户等 |
用户 | USR | 用户基本信息、用户交易、活跃 |
员工 | EMP | 员工、代理人 |
产品 | PRD | 产品基础属性、业务属性、分类 |
渠道 | CHN | 渠道基本信息、分类 |
维度 | DIM | 维度 |
交易 | TXN | 协议、合同 |
数仓层包括DMD和DWS两层。
DWD: 数据规范化处理,包括通用字段规范化处理(命名统一、数据类型统一、数据内容标准化等)、通用码值规范化处理
DWS:按照统一标准命名
数据集市层按照数据主题或者业务含义,进行数据打通和汇总。如:
产品主题(PRODUCT) : PRD
客户主题(CUSTORMER): CUS
权益主题(RIGHTS): RIS
数据应用层根据不同的应用场景进行区分
模型根据每层情况加入技术字段,比如:
表类型: P(分区表) | N(非分区表)
加载方式: F(全量) | T(增量)
周期: D(日) | W(周) | M(月) ...
层级 | 规则 | 示例 |
---|---|---|
ODS | ODS_集团/公司名_表实体_后缀 | ods_xxx_order_info_pfd |
DWD | DWD_集团/公司名_表实体_后缀 | dwd_xxx_order_info_pfd |
DWS | DWS_集团/公司名_主题_表实体_后缀 | dws_xxx_prd_order_info_pfd |
DM | DM_集团/公司名_主题_表实体_后缀 | dm_xxx_prd_order_info_pfd |
符合一般通用的字段命名规范,设置字段长度不超过30。
在整个数据仓库中,必须统一定义
,即所有的逻辑数据模型中不同的表级之间同一名称的字段必须为同一名称。如属性名称为"交易日期",不能在A表中物理化为"TX_DT",在B表中物理化为"TX_DAY"。
除了约定缩写外,英文名应尽量是字段的全称
。单词间用下划线
分隔。
在数据仓库的建设过程中,为防止出现读错误。开发人员应建立标准词根库
,维护并更新该词库。在开发过程中,应优先从词库中选取词组,保证词组的一致性。
码值字段规范
类型 | 格式 | 举例 | 命名 |
---|---|---|---|
xx编码key | STRING | 客户类别代码: 01、02、03 | cus_type_code |
xx编码描述 | STRING | 客户类别代码描述: 个人客户、企业用户、商业用户 | cus_type_desc |
计量字段规范
类型 | 格式 | 描述 | 举例 | 命名 |
---|---|---|---|---|
xx数量 | decimal (20,0) | 客户数、交易数等计算得到的数量类字段 | 交易数: 10000 | xx_cnt |
xx金额 | decimal (28,2) | 交易、转账金额类字段 | 转账金额: 1000 | xx_amt |
xx余额 | decimal (28,2) | 存款、贷款余额类字段 | 存款账户余额:10 | xx_bal |
时间字段规范
类型 | 格式 | 描述 | 举例 | 命名 |
---|---|---|---|---|
日期 | YYYY-MM-DD | 字符串类型的分隔10位数日期格式 | 2021-01-01 | xx_dt |
时间 | YYYY-MM-DD HH:mm:ss | 字符串类型的分隔19位数日期格式 | 2021-01-01 01:01:01 | xx_ts |
参数字段规范
为了方便数据管理,逻辑数据模型中可以存放一些参数
字段:例如开始时间、结束时间、任务编号、数据日期等。
类型 | 格式 | 描述 | 举例 | 命名 |
---|---|---|---|---|
开始时间 | YYYY-MM-DD | 数据开始时间参数 | 2021-01-01 | start_dt |
结束时间 | YYYY-MM-DD | 数据结束时间参数 | 2021-02-01 | end_dt |
源表名 | STRING | 数据来源表参数 | src_table | |
任务编号 | STRING | 调度任务作业编号参数 | job_id | |
数据日期 | YYYY-MM-DD | 数据日期参数 | 20210101 | data_dt |
为保持物理模型的稳定性和合理性,根据业务内容对字段类型进行约束和规范,包括但不限于:
数据类型 | 含义 |
---|---|
STRING | 字符型字段 |
STRING | 较长字符型字段、时间、日期 |
STRING | 通用的交易、产品、渠道、业务等编号;电话号码、手机号码、证件号码、传真号码等 |
STRING | 内容很长的说明、描述字段 |
TIMESTAMP | 时间戳 |
DECIMAL (38) | 大额数字 |
DECIMAL (28, 2) | 金额 |
DECIMAL (28, 8) | 一些利率、汇率等 |
DECIMAL (22, 0) | INT数值 |
DECIMAL (8, 0) | SMALL INT数值 |
数仓建设是每个企业必不可少的数据管理内容,无论是大中厂还是小厂,如何规范化建设数仓,保证集团数据最大价值化,能够快速为业务赋能,是每个数据人都需要考虑的一件事。
本文根据企业级数仓体系架构建设思想,并结合自身数仓建设经验,仅作为抛砖引玉之念,希望可以帮助一些小伙伴。