寒刃尽断处,吾心作剑霜作锋🏂
目录
一、数仓简介
二、关系建模与维度建模
1. 关系建模
2. 维度建模
• 三种模型
• 事实表
• 维度表
3. 事实表的分类
• 事务型事实表
• 周期型快照事实表
• 累积型快照事实表
• 事实表的选择
三、数据仓库建模
1. ODS层
2. DWD层(维度建模)
• 维度建模四部曲
• 用案例讲维度建模
> 选择业务过程
> 声明粒度
> 确定维度
> 确定事实
> 确定维度表
3. DWS层
4. DWT层
5. ADS层
四、数据存储模式
数仓简介
数仓应该包括的功能:存储数据,管理数据,分析计算
为什么搭建数仓:支持BI(Business Intelligence)系统,利用公司数据,发掘潜在的价值,发现数据的规律,总结出规律,指导业务决策
数仓不是数据的终点。
数仓分层层数不固定,各层的名字也不确定。
数仓为什么要分层
:
(1)把复杂问题简单化:数仓分层后,遇到复杂的需求可以较快确认从哪一层查数据,不用从原始表中梳理,写很复杂的SQL,而且后面测试的时候方便定位问题。
(2)减少重复开发:数仓分层后,每一层都有明确的规范对数据进行什么样的处理,当两个需求的前几步都相同时,可以通过数仓的中间层数据直接使用,而不用重复计算,增加一次计算结果的复用性。
(3)隔离原始数据:分层后可以使原始数据和统计数据解耦开来。一方面是可以把原始数据中的非法数据剔除掉,方便后续人员的使用;另一方面是方便进行权限管理,特定的人只能看到特定层的数据,接触不到用户的敏感信息。
关系建模与维度建模
数据处理方式可以分为两大类:
-
联机事务处理OLTP(on-line transaction processing)
业务系统,小量数据的随机增删改查 面向用户,JavaEE项目 数据只保留最新状态
-
联机分析处理OLAP(On-Line Analytical Processing)
数仓,分析型系统,大批量数据的分析汇总 内部分析师,为决策提供支持 保留的数据是随时间变化的历史状态
关系建模
严格遵循第三范式,表数量多,虽然数据冗余程度低,但是在大规模数据跨表分析查询中会进行多次join,效率较低。
维度建模
中间有一张中心表(事实表),四周是关联表(维度表)。可能存在数据冗余,但是能较方便得到数据。
三种模型:
维度建模又分为三种模型:星型模型
、雪花模型、星座模型
事实表
事实表中的每一行数据代表一个业务事件。比如再下单事实表中,一行数据就是一个订单
事实表内容包含两部分,一部分是与维度表相连的外键,一部分是业务事件的度量值(比如在下单事实表中这个度量值就是下单的数量、金额等)。
特点:
内容相对的窄:列数较少。因为事实表中只有两类字段,一类是与维度表相连的外键,一类是度量值。
数据量非常的大。因为事实表对应的是业务事件,业务事件每天有很多。
经常发生变化,每天会新增很多。
维度表
对事实表中的描述信息,一张维度表对应现实世界中的一个对象或者概念。比如时间、客户、产品、地域…
特点:
维度表的范围很宽(具有多个属性、列比较多)因为他把所有与这个维度相关的属性都放在了一张表中。
和事实表相比,行数相对较少:通常<10万条
内容相对固定
为什么要这样设计维度表,或者说是维度建模的意义,为什么要这样组织数据?
我们要知道数据分析一般做的就是汇总,那么汇总就单单得到一个汇总值就可以了吗?比如统计下单数量的时候,我们就只希望得到一个下单数量就完了吗?其实不是这样的,我们通常是带着某一维度去汇总
的。比如统计下单数量的时候,我们通常是某一省份的下单数量,或者是某一时间的下单数量,这里的省份,时间就是维度。
和维度模型联系起来:当我们统计汇总的时候,那个值是什么?或者说我们统计的是谁?其实我们统计的就是业务事件当中的那个度量值。那么我们的统计一般都是一个维度,一个度量值。
比如:我要统计一个省份的下单数量,我只需要将事实表和省份表(维度表)进行关联,然后group by 省份
,select 省份,然后进行聚合函数操作得出每个省份的下单数量。下一步就可以进行前端展示,例如省份下单热点图。
我也可以从其他角度(维度)统计下单数量,比如时间,下单用户的性别,下单用户的年龄…那么这就是维度建模的意义所在。
事实表的分类
事务型事实表
以每个事务或者事件为单位,作为事务型事实表中的一行数据。比如一笔下单记录,一个退货记录。
事务型事实表中,一旦事务被提交,事实表数据被插入,数据就不再进行更改,他的更新方式为增量更新。
周期型快照事实表
周期型快照事实表中不会保留所有数据,只保留固定时间间隔的数据,也就是不关心数据变化的过程,只关心数据变化的结果。比如每天的账户余额。
累积型快照事实表
累计快照事实表用于跟踪业务事实的变化。在这种事实表中,我的一行数据一次性写不完,其中有几个字段的值暂时还没有获取到,当这几个字段的值获取到后我再把这个值填到那一行数据里面去(更新动作)。也就是说我的这一行数据不是一次性写完的,而是累积写完的,所以就叫累积型快照事实表。
因为hive是不支持update语法的,那么这种表是如何修改的?把这条数据所在分区的所有数据都查出来,看哪些数据需要修改,然后在select过程中把这些数据进行修改,修改完之后再insert overwrite回去。这样就更新成功了原有数据。
事实表的选择:
增量表用事务型事实表去做。
对某一个度量值我们只关心最终的结果,而不关心变化的过程,用周期型快照事实表。
对应的事实是一个周期性变化的事实,用累积型快照事实表。
数据仓库建模
ODS层
---- Operation Data Store 原始数据层,存放原始数据
数据保持原貌,不做任何处理。
需要建哪些表是根据导过来的数据建的。
创建分区表,防止后续的全表扫描。
分区表的好处:将整张表的数据放到不同的物理路径下,后面查数据的时候,以分区字段作为过滤条件的话,查询效率是很高的。
数仓为啥要建分区表?因为数仓属于离线计算,那离线是怎么计算呢?比如,我今天计算昨天的数据,明天就计算今天的数据。也就是数据是一天一天的计算的,那么我们直接按天分区,去取那一天的数据就可以了,这样效率就很高了
数据采用压缩,减少磁盘存储空间,每一层都要采用压缩。(本项目采用lzo压缩)。
DWD层
---- Data Warehouse Detail 明细数据层(维度建模只在这一层)
进行维度建模一般指的是业务系统当中的表,而日志数据处理比较简单,因为日志数据是json格式的字符串,我们只需要将json解析成表就可以了。
维度建模一般有四步:选择业务过程 -> 声明粒度 -> 确认维度 -> 确认事实
1 . 选择业务过程
在业务系统中,一条业务线对应一张事实表
选择业务过程之后我们能确定下来的是数仓当中有多少张事实表。
选择业务过程,其实就是在确定数仓中有哪些事实表
2 . 声明粒度
数据粒度就是数仓中的表,保存的数的细化程度或综合程度的级别。我们一般说粗粒度,细粒度。粗粒度的数据就是综合(汇总)程度比较高的数据;原始数据(明细数据)就是细粒度的数据。实际上粒度就是描述数据的聚合程度的。
声明粒度,声明的是事实表的粒度,有一个原则是:应该尽可能选择最小粒度。这个粒度意味着你事实表中的一行数据表示什么,粒度越小,能满足的需求就越多。比如你需求统计出来的粒度比事实表中的粒度都小,也就是说,你要从一个粗粒度的数据统计成细粒度的指标,这不可能实现,为什么呢?因为你粗粒度已经是一个聚合值了,那你还能找到他的详细值吗?这显然不可能。如果说有一份最细粒度的数据,你想给他聚合成任意粒度的数据都可以,因为你这个数据是最细粒度的。因此声明粒度的时候尽可能的选择最小粒度。
3 . 确定维度
确定每一张事实表和哪些维度表是有关联的。
这一步完成后就能够确定事实表中的外键有哪些。
4 . 确定事实
这里的“事实”,指的是事实表中的度量值
,也就是确定事实表中的度量值,因为每个事实表中的度量值是不一样的。
维度建模举例:
1 . 选择业务过程
在电商中我们选取的业务过程有:下单、支付、加入购物车、评论、退款、收藏、领取优惠券
2 . 声明粒度
根据我们的理论,声明粒度的时候我们应该尽可能的声明一个最细的粒度,以此来满足后续各种各样的需求。拿下单业务来说,和下单相关的表有订单表和订单明细表。根据理论我们就应该选订单明细表作为我们声明的粒度。但是我们这个表有点特殊,我们当时选择最细粒度的原因是为了满足后续任意的需求,如果声明较粗的粒度,有一部分需求是满足不了的。
声明最细粒度有没有缺点
呢?粒度越细,说明数据量越大
,明细数据肯定比汇总数据多。当我要做需求计算的时候,都要从原始数据查,那么计算量比较大,计算的代价就比较高
所以在实际的开发中,不会完全的遵循理论(不等于不遵循理论),要有适当的变通。比如再插入一张较粗
粒度的表(不能只有一张较粗粒度的表),适当的进行宽表化处理,那么订单业务就有两张表,一张是最细粒度的订单明细表,一张是较粗粒度的订单信息表。这样的话,后面再做需求的时候就可以从较粗粒度的订单信息表中查,因为他数据量少,计算速度也就快,如果说是这个粗粒度的表满足不了这个需求,那我就从细粒度的订单明细表查。这样设计的话就能在一定程度上提高查询的性能。
3 . 确定维度
确定每一张事实表跟哪些维度相关,一般是先把所有的维度列出来。那维度怎么确定呢?维度会作为后续观察数据的角度,你肯定知道后续要从哪些角度观察数据。比如:后面我要统计每个省份的销售额,那么省份就是一个维度。
列出维度:
确定维度:
4 . 确定事实
确定事实表当中的度量字段,一个事实表当中的度量值可以有多个。
上图中的那个表专业名词叫做业务总线矩阵
通过上面的四步,我们已经确定了维度模型中所有的事实表,有哪些外键和度量值。
5 . 确定维度表
接下来我们怎么确定维度表
呢?我们现在只知道有哪些维度,这些维度表中有哪些字段我们应该怎么确定?其实就是把跟这个维度相关的表汇总到一张大宽表里面(这个过程叫做维度退化
),这个大宽表就作为我们的维度表。而这个大宽表里面会有所有和这个主题相关的度量值(事实)的统计值。
与各个维度表相关的表如下:
至此,数仓的维度建模已经完毕,后续几层已经和维度建模没有关系了
数仓当中有了维度模型后,就可以应对各种各样的需求,因为维度模型当中主体是事实表,而事实表是最细粒度的数据,有了最细粒度的数据后,什么样聚合程度的需求都可以从DWD层实现,那么建立后面几层的目的是什么?
其实是为了优化数仓的结构
,虽然我们DWD层的维度模型能够应对所有的需求,但是如果所有的需求都从DWD层查数据,查是能查出来,但是性能比较差。因为DWD层存的都是明细数据,也就是细粒度的数据,数据量大,查的话计算量比较大还有就是可能出现重复计算的问题,因此会导致他的性能降低。
DWS层
----Data Warehouse Service 服务数据层按照主题去建宽表,统计各个主题对象当天的行为。
主题就是分析问题的角度,也就是维度。每个主题下面会有和这个主题相关的所有的度量值的统计结果。
这一层建立的是分区表,按天分区。
DWT层
----Data Warehouse Topic 数据主题层这一层和DWS层一一对应,只不过这一层统计的是累积行为
,某种程度上可以说是每张主题宽表里面存的是全量的主题对象。比如说统计的是最近7天的,最近30天的,最近一个季度的,最近一年的,从开始到现在的…
在这一层建立的是一张大表,这张大表每天都会更新。
ADS层
----Application Data Store 服务应用层这一层为数仓应用提供服务,例如报表系统,数据挖掘,机器学期,用户画像… ,如果对接的是报表系统,那这一层就要存储和报表相关的数据,例如报表系统中所需要的各个指标的统计结果。
数据存储模式
我们每一层表下面的数据是什么状态呢?
我们已经将采集到的数据存放在HDFS上的某个路径下。
那么ODS层中的数据是将HDFS上某个路径下的数据load到ODS层这个表指定的一个路径下边。在HDFS上Hive的load操作相当于是剪切,load后,原来那个路径下的数据就没了,就load到ODS层中那个表所在的路径下了。这样也符合ODS层的功能,存放原始数据,保持数据原貌。
DWD层是从ODS层select,这个过程中需要对数据进行汇总,解析,处理完之后insert into 或insert overwrite到DWD层的表里面。这样DWD层也会有自己的新数据,只不过这个数据和之前的数据是不一样的,是DWD层的数据了。这时ODS层的数据还在。
同样的,DWS的数据是查的DWD的…
这就是数仓当中数据的存储模式了。既不是单纯的复制,也不是引用,而是每一层都有自己的数据。