前言
数据仓库建模包含了几种数据建模技术,除了之前在数据库系列中介绍过的ER建模和关系建模,还包括专门针对数据仓库的维度建模技术。
本文将详细介绍数据仓库维度建模技术,并重点讨论三种基于ER建模/关系建模/维度建模的数据仓库总体建模体系:规范化数据仓库,维度建模数据仓库,以及独立数据集市。
维度建模的基本概念
维度建模(dimensional modeling)是专门用于分析型数据库、数据仓库、数据集市建模的方法。
它本身属于一种关系建模方法,但和之前在操作型数据库中介绍的关系建模方法相比增加了两个概念:
1、 维度表(dimension)
表示对分析主题所属类型的描述。比如”昨天早上张三在京东花费200元购买了一个皮包”。那么以购买为主题进行分析,可从这段信息中提取三个维度:时间维度(昨天早上),地点维度(京东), 商品维度(皮包)。通常来说维度表信息比较固定,且数据量小。
2、 事实表(fact table)
表示对分析主题的度量。比如上面那个例子中,200元就是事实信息。事实表包含了与各维度表相关联的外码,并通过JOIN方式与维度表关联。事实表的度量通常是数值类型,且记录数会不断增加,表规模迅速增长。
注:在数据仓库中不需要严格遵守规范化设计原则(具体原因请看上篇)。本文示例中的主码,外码均只表示一种对应关系,此处特别说明。
维度建模的三种模式
1、 星形模式
星形模式(Star Schema)是最常用的维度建模方式,下图展示了使用星形模式进行维度建模的关系结构:
可以看出,星形模式的维度建模由一个事实表和一组维表成,且具有以下特点:
a. 维表只和事实表关联,维表之间没有关联;
b. 每个维表的主码为单列,且该主码放置在事实表中,作为两边连接的外码;
c. 以事实表为核心,维表围绕核心呈星形分布;
2、 雪花模式
雪花模式(Snowflake Schema)是对星形模式的扩展,每个维表可继续向外连接多个子维表。下图为使用雪花模式进行维度建模的关系结构:
星形模式中的维表相对雪花模式来说要大,而且不满足规范化设计。雪花模型相当于将星形模式的大维表拆分成小维表,满足了规范化设计。然而这种模式在实际应用中很少见,因为这样做会导致开发难度增大,而数据冗余问题在数据仓库里并不严重。
3、 星座模式
星座模式(Fact Constellations Schema)也是星型模式的扩展。基于这种思想就有了星座模式:
前面介绍的两种维度建模方法都是多维表对应单事实表,但在很多时候维度空间内的事实表不止一个,而一个维表也可能被多个事实表用到。在业务发展后期,绝大部分维度建模都采用的是星座模式。
4. 三种模式对比
归纳一下,星形模式/雪花模式/星座模式的关系如下图所示:
雪花模式是将星型模式的维表进一步划分,使各维表均满足规范化设计。而星座模式则是允许星形模式中出现多个事实表。本文后面部分将具体讲到这几种模式的使用,请读者结合实例体会。
实例:零售公司销售主题的维度建模
在进行维度建模前,首先要了解用户需求。而笔者在数据库系列的第一篇就讲过,ER建模是当前收集和可视化需求的最佳技术。因此假定和某零售公司进行多次需求PK后,得到以下ER图:
随后可利用建模工具将ER图直接映射到关系图:
需求搜集完毕后,便可进行维度建模了。本例采用星形模型维度建模。但不论采取何种模式,维度建模的关键在于明确下面四个问题:
1、 哪些维度对主题分析有用?
本例中,根据产品(PRODUCT)、顾客(CUSTOMER)、商店(STORE)、日期(DATE)对销售额进行分析是非常有帮助的;
2、 如何使用现有数据生成维表?
a. 维度PRODUCT可由关系PRODUCT,关系VENDOR,关系CATEGORY连接得到;
b. 维度CUSTOMER和关系CUSTOMER相同;
c. 维度STORE可由关系STROE和关系REGION连接得到;
d. 维度CALENDAR由关系SALESTRANSACTION中的TDate列分离得到;
3、 用什么指标来”度量”主题?
本例的主题是销售,而销量和销售额这两个指标最能直观反映销售情况;
4、 如何使用现有数据生成事实表?
销量和销售额信息可以由关系SALESTRANSACTION和关系SOLDVIA,关系PRODUCT连接得到;
明确这四个问题后,便能轻松完成维度建模:
细心的读者会发现三个问题:1. 维表不满足规范化设计(不满足3NF);2. 事实表也不满足规范化设计(1NF都不满足);3. 维度建模中各维度的主码由***ID变成***Key;
对于前两个问题,由于当前建模环境是数据仓库,而没有更新操作,所以不需要严格做规范化设计来消除冗余避免更新异常。
因此虽然可以以雪花模型进行维度建模,如下所示:
但这样会加大查询人员负担:每次查询都涉及到太多表了。因此在实际应用中,雪花模型仅是一种理论上的模型。星座模型则出现在”维度建模数据仓库”中,本文后面将会讲到。
对于第三个问题,***Key这样的字段被称为代理码(surrogate key),它是一个通过自动分配整数生成的主码,没有任何其他意义。使用它主要是为了能够处理”缓慢变化的维度”,本文后面会仔细分析这个问题,这里不纠结。
更多可能的事实属性
除了对应到维度的外码和度量属性,事实表中还常常考虑另外两个属性:事务标识码(transaction identifier)和事务时间(transaction time)。
事务标识码通常被命名为TID,其意义就是各种订单号,事务编号…… 为什么将这个属性放到事实表而不是维表中呢?一个主要原因是它的数量级太大了,这样每次查询都会耗费很多资源来Join。这种将某些逻辑意义上的维度放到事实表里的做法被称为退化维度(degenerate dimension)。
将事务时间维度放到事实表中的考虑也是出于相同考虑。然而这么设计又一次”逆规范化”了:事务标识码非主码却决定事务标识时间,显然违背了3NF。但现在我们是为数据仓库建模,所以这样做是OK的。另外在分布式的数据仓库中,这个字段十分重要。因为事实表的数量级非常大,Hive或者Spark SQL这类分布式数据仓库工具都会对这些数据进行分区。任何成熟的分布式计算平台中都应禁止开发人员建立非分区事实表,并默认分区字段为(当天)日期。
经典星座模型
前文已经讲过,有多个事实表的维度模型被称为星座模型。星座模型主要有以下两大作用:共享维度和设置细节/聚集事实表。下面分别对这两种情况进行分析:
1、 共享维度
以前文提到的零售公司为例,假如该公司质量监管部门希望用分析销售主题同样的方法分析劣质产品,那么此时不需要重新维度建模,只需往模型里加入一个新的劣质产品事实表。之后新的数据仓库维度建模结果如下:
2、 细节/聚集事实表
细节事实表(detailed fact tables)中每条记录表示单一事实,而聚集事实表(aggregated fact tables)中每条记录则聚合了多条事实。从表的字段上看,细节事实表通常有设置TID属性,而聚集事实表则无。
两种事实表各有优缺点,细节事实表查询灵活但是响应速度相对慢,而聚集事实表虽然提高了查询速度,但使查询功能受到一定限制。一个常见的做法是使用星座模型同时设置两种事实表(可含多个聚集事实表)。这种设计方法中,聚集事实表使用和细节事实表细节事实表的维度。如下维度建模方法采用星座模型综合了细节事实表和两种聚集事实表:
缓慢变化维度问题
虽然,维表的数据比事实表更稳定。但不论如何维度在某些时候总会发生一些变化。在之前曾抛出一个问题:为什么维度建模后的关系不是***ID,而是***Key了。这样做的目的其实就是为了解决一种被称为缓慢维度变化(slowly changing dimension)的问题。在维度变化后,一部分历史信息就被丢掉了。比如张三是某公司会员。
但仅仅这么做还是不够的,代理码需要配合时间戳,以及行标识符使用才能解决缓慢维度变化的问题。如下CUSTOMER表使用该方法避免缓慢维度变化:
可以看到用户张三对应新维度的TaxBracket状态由Low变成了High。如果需要统计张三的相关行为,那么可以让所有记录用CustomerID字段Join事实表;如果要统计当前TaxBracket为Low的用户状态,则可将Row Indicator字段为Current的记录用CustomerKey字段Join事实表;如果要统计历史TaxBracket状态为Low的用户情况,则只需要将TaxBracket属性为Low的用户记录的CustomerKey属性与事实表关联。
数据仓库建模体系之规范化数据仓库
所谓”数据仓库建模体系”,指的是数据仓库从无到有的一整套建模方法。最常见的三种数据仓库建模体系分别为:规范化数据仓库,维度建模数据仓库,独立数据集市。很多书将它们称为”数据仓库建模方法”,但笔者认为数据仓库建模体系更能准确表达意思,请允许我自作主张一次吧:)。下面首先来介绍规范化数据仓库。
规范化数据仓库(normalized data warehouse)顾名思义,其中是规范化设计的分析型数据库,然后基于这个数据库为各部门建立数据集市。总体架构如下图所示:
该建模体系首先对ETL得到的数据进行ER建模,关系建模,得到一个规范化的数据库模式。然后用这个中心数据库为公司各部门建立基于维度建模的数据集市。各部门开发人员大都从这些数据集市提数,通常来说不允许直接访问中心数据库。
数据仓库建模体系之维度建模数据仓库
非维度建模数据仓库(dimensionally modeled data warehouse)是一种使用交错维度进行建模的数据仓库,其总体架构如下图所示:
该建模体系首先设计一组常用的度集合(conformed dimension),然后创建一个大星座模型表示所有分析型数据。如果这种一致维度不满足某些数据分析要求,自然也可在数据仓库之上继续构建新的数据集市。
数据仓库建模体系之独立数据集市
独立数据集市的建模体系是让公司的各个组织自己创建并完成ETL,自己维护自己的数据集市。其总体架构如下图所示:
从技术上来讲这是一种很不值得推崇的方式,因为将使信息分散,影响了企业全局范围内数据分析的效率。此外,各组织之间的ETL架构相互独立无法复用,也浪费了企业的开发资源。然而出于某些公司制度及预算方面的考虑,有时也会使用到这种建模体系。
三种数据仓库建模体系对比
规范化数据仓库和维度建模数据仓库分别是Bill Inmon和Ralph Kimball提出的方法。关于哪种方法更好,哪种方法更优秀的争论已经由来已久。但随着这两种数据仓库应用越来越多,人们也逐渐了解到两种数据仓库的优劣之处,如下表所示:
产生这些区别的根本之处在于规范化数据仓库需要对企业全局进行规范化建模,这将导致较大的工作量。但这一步必须完成好,才能继续往上建设数据集市。因此也就导致规范化数据仓库需要一定时间才能投入使用,敏捷性相对后者来说略差。但是规范化数据仓库一旦建立好了,则以后数据就更易于管理。而且由于开发人员不能直接使用其中心数据库,更加确保了数据质量。还有由于中心数据库是采用规范化设计的,冗余情况也会更少。
然而另一方面维度建模数据仓库除了敏捷性更强,而且适用于业务变化比较频繁的情况,对开发人员的要求也没有规范化数据仓库那么高。总之各有利弊,具体实施时需要仔细的权衡。
数据仓库分层
DW :data warehouse 翻译成数据仓库
DW数据分层,由下到上为 DWD,DWB,DWS
DWD:data warehouse detail 细节数据层,有的也称为 ODS层,是业务层与数据仓库的隔离层
DWB:data warehouse base 基础数据层,存储的是客观数据,一般用作中间层,可以认为是大量指标的数据层。
DWS:data warehouse service 服务数据层,基于DWB上的基础数据,整合汇总成分析某一个主题域的服务数据,一般是宽表。
宽表:意思是 把很多的 维度、指标都合到一个表里,需要冗余,为了后续数据统计方便,宽表由于把不同的内容都放在同一张表存储,宽表已经不符合三范式的模型设计规范,随之带来的主要坏处就是数据的大量冗余,与之相对应的好处就是查询性能的提高与便捷。
什么是维度建模
维度建模是一种重新组织业务数据提供分析的方式,把数据最终分成两类:
- 事实表:存储了基础事件,是数据分析的主要数据,如订单的明细。
- 维度表:存储了事实相关的详细数据,如订单中的店铺信息、品牌信息等。
Kimball维度建模的整体架构如下:
源系统就是数据来源,往往部署分散、类型繁多;ETL是最复杂的一部分,稍后会详细整理;维度数仓的产出是维度表和事实表;BI应用则是基于数仓构建出的报表、分析、业务应用等。
维度建模相关技术
在构建维度建模前,需要做好几部分的工作:
- 收集业务需求和数据:了解业务的操作过程,在运营过程中的希望数据给出哪些指导和判断,了解源数据的格式、数据量、关联方法等。
-
维度设计:需要确定建模的粒度、相关的维度、相关的事实。其中粒度就是业务关注的最细粒度,比如订单里面一般是订单明细行,商品维度则需要到sku级别;维度描述了事实发生的环境,需要能回答谁、什么、何时、何地、为什么、如何等问题;事实则是统计的基础,需要能支撑到所有的关注点。
事实表和维度表在设计时,需要考虑很多问题:
- 代理键问题:为维度的每一条数据设置一个主键,标识唯一一条,方便事实表关联。我们在工作中一般维度表会每天存储一份最新数据(牺牲空间换效率),这样仅仅依赖业务主键+日期就可以完成代理键的工作
- 自然键和持久键:自然键是业务系统中的主键,在一些场景中如,员工离职复职,自然键发生变化,但是如果想标识为同一个人,可以通过在数仓创建持久键把他们关联起来,统一标识。
- 退化维:当事实中涉及到一些编号,却没有维度与之关联,那么这些编号可以放入事实中,方便查询过滤。(一般都有维度,暂时没有接触到退化维的场景)
- 非规范化扁平维度:常见的如分类,一般的电商或者实体都会有分类层级的概念,一级分类、二级分类、三级分类等,为了方便使用,一般会把他们组织到同一个维度表中,通过简单的去重方式使用,避免多层关联。
- 空值处理:一般对于空值,可以设置一个默认值,如unknow,其他等,避免Null引起的各种sql查询问题
- 支架维度:一般用于多个维度之间的关联,这种维度设计一般不推荐,最好还是直接通过事实维度来进行关联。
- 缓慢变化维:slowly changing dimension, scd,是维度建模中最重要的一种技术。缓慢变化为是指数据随着时间会有不同的变化,如何记录这种变化采用的技术。典型的场景如订单随着时间会有不同的状态,创建-支付-核销-退货等;活动品在一场活动中也会随时调整价格。一般采用的的方法是:1 重写(发生变化后重写数据仓库,把相关数据修改成变化后的样子)2 新增(新增一行来描述最新的结果,但是使用的时候需要针对同一条数据去重,因此要考虑如何去重问题)3 增加列(在数据中增加一列原值,每次修改的时候新增一条数据,原值列放入上一次修改的值)。第二种方式是使用最多的方法。
维度建模生命周期
关于维度建模的整体生命周期,书中给出了一个非常清晰的指导图:
项目规划:项目规划期需要考虑整体的开展思路、目标、周期,涉及的业务人员、开发人员、最后的使用人员,并随时拉起会议讨论相关问题;
需求定义:此阶段主要是了解业务背景、流程、需求、目标、输出,一般是最耗时的阶段,经常开会开着开着就扯的天南海北,因此会议的组织者一定要随时明确会议的主要目标,避免浪费时间。最终形成产出文档、明确各环节的优先级。
技术架构:目前大数据方案的技术架构基本稳定了,如果是离线应用:数据抽取一般会使用sqoop、数据的ETL一般会使用spark、数据的存储一般是hive+paquet、任务的调度监控是oozie;如果是实时应用:数据的抽取一般会使用canal或者streamsets,存储使用kafka,ETL使用flink,落地存储则是hbase或者db。如果是长期做数据应用,一般不需要重新部署,这些都是可复用的资源。
维度建模:前面一章已经整理过了,确定粒度、事实和维度,避免使用太多的数据库范式的思维。书中描述的维度建模输出内容非常好,仅供参考:
ETL:后面详细介绍。
应用设计:最初需求定义好,维度建模完成,应用的设计就很简单了。使用好数据,以满足需求的方式存储展现就行。
后面就无尽的迭代和维护。
ETL相关技术
一般说到ETL很直白的就会想到数据抽取、转换、加载,其实完整的数据仓库涉及到的ETL技术还是非常多的。
4、1 数据抽取阶段:
数据分析:首先要分析数据的规模、各个字段的含义、值的类型以及分布,对数据有一个简单的了解
变化数据获取:change data capture, CDC。一般有几种方式:1 基于binlog做实时获取,如canal、streamsets等通过分析数据库的binlog可以获取所有的变更数据,一般在实时数仓时常用;2 基于变化时间获取,如每个表增加一个modify_time,这个时间会在数据记录发生变化的时候自动更新,每天按照Modify_time进行增量抽取。缺点是一天当中的变化只能记录最后的变化结果、删除数据无法感知。
4、2 数据清洗阶段:
数据质量监控:当遇到非法数据,如空值、电话号违规等,采取丢弃、告警、停止等行为,需要记录这些事件,方便后面溯源。
重复数据管理:抽取数据后,有可能会出现重复数据,一般的方法是采用数据切片的方式,每天维护最新版本,从而实现通过时间去重保留最新数据。
一致性管理:当涉及到多个系统,有可能会出现数据不一致的情况,此时可以在最后增加一致性判断
4、3 数据展现阶段:
缓慢变化维的管理:这个前面说过了。代理键生成;迟到数据处理等。
除了前面的ETL涉及的技术,在日常管理方面,还会涉及到很多周边技术:
任务调度:需要提供任务的定时执行、失败监控告警、任务依赖等特性
备份系统:时刻对数据进行备份,避免数据丢失
版本控制:数据需求的代码需要记录历史版本
安全系统:如果是多部门注重安全,那么需要考虑数据的安全性,一般采用sentry实现
如何优雅地设计数据分层
- 数据建设刚起步,大部分的数据经过粗暴的数据接入后就直接对接业务。
- 数据建设发展到一定阶段,发现数据的使用杂乱无章,各种业务都是从原始数据直接计算而得。
- 各种重复计算,严重浪费了计算资源,需要优化性能。
#
如何优雅地设计数据分层
最初在做数据仓库的时候遇到了很多坑,由于自身资源有限,接触数据仓库的时候,感觉在互联网行业里面的数据仓库成功经验很少,网上很难找到实践性比较强的资料。而那几本经典书籍里面又过于理论,折腾起来真是生不如死。还好现在过去了那个坎,因此多花一些时间整理自己的思路,帮助其他的小伙伴少踩一些坑。文章的结构如下:
1、 为什么要分层?这个问题被好几个同学质疑过。因此分层的价值还是要说清楚的。
2、 分享一下经典的数据分层模型,以及每一层的数据的作用和如何加工得来。
3、 分享两个数据分层的设计,通过这两个实际的例子来说明每一层该怎么存数据。
4、 给出一些建议,不是最好的,但是可以做参考。
0x01 为什么要分层
我们对数据进行分层的一个主要原因就是希望在管理数据的时候,能对数据有一个更加清晰的掌控,详细来讲,主要有下面几个原因:
1、 清晰数据结构:每一个数据分层都有它的作用域,这样我们在使用表的时候能更方便地定位和理解。
2、 数据血缘追踪:简单来讲可以这样理解,我们最终给业务诚信的是一能直接使用的张业务表,但是它的来源有很多,如果有一张来源表出问题了,我们希望能够快速准确地定位到问题,并清楚它的危害范围。
3、 减少重复开发:规范数据分层,开发一些通用的中间层数据,能够减少极大的重复计算。
4、 把复杂问题简单化。讲一个复杂的任务分解成多个步骤来完成,每一层只处理单一的步骤,比较简单和容易理解。而且便于维护数据的准确性,当数据出现问题之后,可以不用修复所有的数据,只需要从有问题的步骤开始修复。
5、 屏蔽原始数据的异常。
6、 屏蔽业务的影响,不必改一次业务就需要重新接入数据。
数据体系中的各个表的依赖就像是电线的流向一样,我们都希望它是规整、流向清晰、便于管理的,如下图:
但是,最终的结果大多却是依赖复杂、层级混乱,想梳理清楚一张表的声称途径会比较困难,如下图:
0x02 怎样分层
一、理论
我们从理论上来做一个抽象,可以把数据仓库分为下面三个层,即:数据运营层、数据仓库层和数据产品层。
1、 ODS 全称是 Operational Data Store,操作数据存储
“面向主题的”,数据运营层,也叫ODS层,是最接近数据源中数据的一层,数据源中的数据,经过抽取、洗净、传输,也就说传说中的 ETL 之后,装入本层。本层的数据,总体上大多是按照源头业务系统的分类方式而分类的。
但是,这一层面的数据却不等同于原始数据。在源数据装入这一层时,要进行诸如去噪(例如有一条数据中人的年龄是 300 岁,这种属于异常数据,就需要提前做一些处理)、去重(例如在个人资料表中,同一 ID 却有两条重复数据,在接入的时候需要做一步去重)、字段命名规范等一系列操作。
2、 数据仓库层(DW),是数据仓库的主体
在这里,从 ODS 层中获得的数据按照主题建立各种数据模型。这一层和维度建模会有比较深的联系,可以多参考一下前面的几篇文章。
3、 数据产品层(APP),这一层是提供为数据产品使用的结果数据
在这里,主要是提供给数据产品和数据分析使用的数据,一般会存放在 ES、Mysql 等系统中供线上系统使用,也可能会存在 Hive 或者 Druid 中供数据分析和数据挖掘使用。
比如我们经常说的报表数据,或者说那种大宽表,一般就放在这里。
二、技术实践
这三层技术划分,相对来说比较粗粒度,后面我们会专门细分一下。在此之前,先聊一下每一层的数据一般都是怎么流向的。这里仅仅简单介绍几个常用的工具,侧重中开源界主流。
1、 数据来源层→ ODS层
这里其实就是我们现在大数据技术发挥作用的一个主要战场。 我们的数据主要会有两个大的来源:
1、 业务库,这里经常会使用 Sqoop 来抽取,比如我们每天定时抽取一次。在实时方面,可以考虑用 Canal 监听 Mysql 的 Binlog,实时接入即可。
2、 埋点日志,线上系统会打入各种日志,这些日志一般以文件的形式保存,我们可以选择用 Flume 定时抽取,也可以用用 Spark Streaming 或者 Storm 来实时接入,当然,Kafka 也会是一个关键的角色。
3、 其它数据源会比较多样性,这和具体的业务相关,不再赘述。
注意: 在这层,理应不是简单的数据接入,而是要考虑一定的数据清洗,比如异常字段的处理、字段命名规范化、时间字段的统一等,一般这些很容易会被忽略,但是却至关重要。特别是后期我们做各种特征自动生成的时候,会十分有用。后续会有文章来分享。
2、 ODS、DW → App层
这里面也主要分两种类型:
1、 每日定时任务型:比如我们典型的日计算任务,每天凌晨算前一天的数据,早上起来看报表。 这种任务经常使用 Hive、Spark 或者生撸 MR 程序来计算,最终结果写入 Hive、Hbase、Mysql、Es 或者 Redis 中。
2、 实时数据:这部分主要是各种实时的系统使用,比如我们的实时推荐、实时用户画像,一般我们会用 Spark Streaming、Storm 或者 Flink 来计算,最后会落入 Es、Hbase 或者 Redis 中。
0x03 举个例子
网上的例子很多,就不列了,只举个笔者早期参与设计的数据分层例子。分析一下当初的想法,以及这种设计的缺陷。上原图和内容。
当初的设计总共分了 6 层,其中去掉元数据后,还有5层。下面分析一下当初的一个设计思路。
缓冲层(buffer)
- 概念:又称为接口层(stage),用于存储每天的增量数据和变更数据,如Canal接收的业务变更日志。
- 数据生成方式:直接从kafka接收源数据,需要业务表每天生成update,delete,inseret数据,只生成insert数据的业务表,数据直接入明细层
- 讨论方案:只把canal日志直接入缓冲层,如果其它有拉链数据的业务,也入缓冲层。
- 日志存储方式:使用impala外表,parquet文件格式,方便需要MR处理的数据读取。
- 日志删除方式:长久存储,可只存储最近几天的数据。讨论方案:直接长久存储
- 表schema:一般按天创建分区
- 库与表命名。库名:buffer,表名:初步考虑格式为:buffer
日期
业务表名,待定。
明细层(ODS, Operational Data Store,DWD: data warehouse detail)
- 概念:是数据仓库的细节数据层,是对STAGE层数据进行沉淀,减少了抽取的复杂性,同时ODS/DWD的信息模型组织主要遵循企业业务事务处理的形式,将各个专业数据进行集中,明细层跟stage层的粒度一致,属于分析的公共资源
- 数据生成方式:部分数据直接来自kafka,部分数据为接口层数据与历史数据合成。
canal日志合成数据的方式待研究。 - 讨论方案:canal数据的合成方式为:每天把明细层的前天全量数据和昨天新数据合成一个新的数据表,覆盖旧表。同时使用历史镜像,按周/按月/按年 存储一个历史镜像到新表。
- 日志存储方式:直接数据使用impala外表,parquet文件格式,canal合成数据为二次生成数据,建议使用内表,下面几层都是从impala生成的数据,建议都用内表+静态/动态分区。
- 日志删除方式:长久存储。
- 表schema:一般按天创建分区,没有时间概念的按具体业务选择分区字段。
-
库与表命名。库名:ods,表名:初步考虑格式为ods
日期
业务表名,待定。
- 旧数据更新方式:直接覆盖
轻度汇总层(MID或DWB, data warehouse basis)
- 概念:轻度汇总层数据仓库中DWD层和DM层之间的一个过渡层次,是对DWD层的生产数据进行轻度综合和汇总统计(可以把复杂的清洗,处理包含,如根据PV日志生成的会话数据)。轻度综合层与DWD的主要区别在于二者的应用领域不同,DWD的数据来源于生产型系统,并未满意一些不可预见的需求而进行沉淀;轻度综合层则面向分析型应用进行细粒度的统计和沉淀
- 数据生成方式:由明细层按照一定的业务需求生成轻度汇总表。明细层需要复杂清洗的数据和需要MR处理的数据也经过处理后接入到轻度汇总层。
- 日志存储方式:内表,parquet文件格式。
- 日志删除方式:长久存储。
- 表schema:一般按天创建分区,没有时间概念的按具体业务选择分区字段。
-
库与表命名。库名:dwb,表名:初步考虑格式为:dwb
日期
业务表名,待定。
- 旧数据更新方式:直接覆盖
主题层(DM,data market或DWS, data warehouse service)
- 概念:又称数据集市或宽表。按照业务划分,如流量、订单、用户等,生成字段比较多的宽表,用于提供后续的业务查询,OLAP分析,数据分发等。
- 数据生成方式:由轻度汇总层和明细层数据计算生成。
- 日志存储方式:使用impala内表,parquet文件格式。
- 日志删除方式:长久存储。
- 表schema:一般按天创建分区,没有时间概念的按具体业务选择分区字段。
-
库与表命名。库名:dm,表名:初步考虑格式为:dm
日期
业务表名,待定。
- 旧数据更新方式:直接覆盖
应用层(App)
- 概念:应用层是根据业务需要,由前面三层数据统计而出的结果,可以直接提供查询展现,或导入至Mysql中使用。
- 数据生成方式:由明细层、轻度汇总层,数据集市层生成,一般要求数据主要来源于集市层。
- 日志存储方式:使用impala内表,parquet文件格式。
- 日志删除方式:长久存储。
- 表schema:一般按天创建分区,没有时间概念的按具体业务选择分区字段。
- 库与表命名。库名:暂定apl,另外根据业务不同,不限定一定要一个库。
- 旧数据更新方式:直接覆盖。
0x04 如何更优雅一些
前面提到的一种设计其实相对来讲已经很详细了,但是可能层次会有一点多,而且在区分一张表到底该存放在什么位置的时候可能还有不小的疑惑。我们在这一章里再设计一套数据仓库的分层,同时在前面的基础上加上维表和一些临时表的考虑,来让我们的方案更优雅一些。
下图,做了一些小的改动,我们去掉了上一节的Buffer层,把数据集市层和轻度汇总层放在同一个层级上,同时独立出来了维表和临时表。
这里解释一下DWS、DWD、DIM和TMP的作用。
- DWS:轻度汇总层,从ODS层中对用户的行为做一个初步的汇总,抽象出来一些通用的维度:时间、ip、id,并根据这些维度做一些统计值,比如用户每个时间段在不同登录ip购买的商品数等。这里做一层轻度的汇总会让计算更加的高效,在此基础上如果计算仅7天、30天、90天的行为的话会快很多。我们希望80%的业务都能通过我们的DWS层计算,而不是ODS。
- DWD:这一层主要解决一些数据质量问题和数据的完整度问题。比如用户的资料信息来自于很多不同表,而且经常出现延迟丢数据等问题,为了方便各个使用方更好的使用数据,我们可以在这一层做一个屏蔽。
- DIM:这一层比较单纯,举个例子就明白,比如国家代码和国家名、地理位置、中文名、国旗图片等信息就存在DIM层中。
- TMP:每一层的计算都会有很多临时表,专设一个DWTMP层来存储我们数据仓库的临时表。
0x05 问答
有朋友问了一些问题,有一些之前的确没讲清楚,补到这里。
问答一: dws 和 dwd 的关系
问:dws 和dwd 是并行而不是先后顺序?
答:并行的,dw 层
问:那其实对于同一个数据,这两个过程是串行的?
答:dws 会做汇总,dwd 和 ods 的粒度相同,这两层之间也没有依赖的关系
问:对呀,那这样 dws 里面的汇总没有经过数据质量和完整度的处理,或者单独做了这种质量相关的处理,为什么不在 dwd 之上再做汇总呢?我的疑问其实就是,dws的轻度汇总数据结果,有没有做数据质量的处理?
答:ods 直接到 dws 就好,没必要过 dwd,我举个例子,你的浏览商品行为,我做一层轻度汇总,就直接放在 dws 了。但是你的资料表,要从好多表凑成一份,我们从四五份个人资料表中凑出来了一份完整的资料表放在了 dwd 中。然后在 app 层,我们要出一张画像表,包含用户资料和用户近一年的行为,我们就直接从dwd中拿资料, 然后再在 dws 的基础上做一层统计,就成一个app表了。当然,这不是绝对,dws 和 dwd 有没有依赖关系主要看有没有这种需求。
问答二: ods 和 dwd 的区别
问:还是不太明白 ods 和 dwd 层的区别,有了 ods 层后感觉 dwd 没有什么用了。
答:嗯,我是这样理解的,站在一个理想的角度来讲,如果 ods 层的数据就非常规整,基本能满足我们绝大部分的需求,这当然是好的,这时候 dwd 层其实也没太大必要。 但是现实中接触的情况是 ods 层的数据很难保证质量,毕竟数据的来源多种多样,推送方也会有自己的推送逻辑,在这种情况下,我们就需要通过额外的一层 dwd 来屏蔽一些底层的差异。
问:我大概明白了,是不是说 dwd 主要是对 ods 层做一些数据清洗和规范化的操作,dws 主要是对 ods 层数据做一些轻度的汇总?
答:对的,可以大致这样理解。
问答三:app 层是干什么的?
问:感觉数据集市层是不是没地方放了,各个业务的数据集市表是应该在 dwd 还是在 app?
答:这个问题不太好回答,我感觉主要就是明确一下数据集市层是干什么的,如果你的数据集市层放的就是一些可以供业务方使用的宽表表,放在 app 层就行。如果你说的数据集市层是一个比较泛一点的概念,那么其实 dws、dwd、app 这些合起来都算是数据集市的内容。
问:那存到 Redis、ES 中的数据算是 app层吗?
答:算是的,我个人的理解,app 层主要存放一些相对成熟的表,能供业务侧使用的。这些表可以在 Hive 中,也可以是从 Hive 导入 Redis 或者 ES 这种查询性能比较好的系统中。
0xFF 总结
数据分层是数据仓库非常重要的一个环节,它决定的不仅仅是一个层次的问题,还直接影响到血缘分析、特征自动生成、元数据管理等一系列功能的建设。因此适于尽早考虑。
另外,每一层的名字不必太过在意,自己按照喜好就好。
本文分享了笔者自己对数据仓库的一些理解和想法,不一定准确也不一定通用,但是可以作为一个参考的思路。有什么问题欢迎多交流。