大数据之路—— 维度设计
作者:互联网
十、数据模型篇—— 维度设计
10.1 维度设计基础
10.1.1 基本概念
维度是维度建模的基础和灵魂,将度量称为”事实“,环境描述为“维度”,用于分析事实所需要的多样环境。
- 维度的作用:一般用来查询约束、分类汇总以及排序
- 维度所包含的表示维度的列,称为维度属性,经常出现在查询中的”按照“(by)语句内,是查询约束条件、分组和报表标签生成的基本来源,数据易用性的关键。如按照月份、产品类型等
- 维度使用主键标识唯一性,主键是确保和他相连的事实表之间存在引用完整性的基础,主键有两种:都是用于标识某维度的具体值。
- 代理键:不具有业务含义的键,一般用来处理缓慢变化的维度
- 自然键:具有业务含义。比如商品,在ETL中对于商品维表的每一行,可以生成一个唯一的代理键与之对应;商品本身的自然键可能是商品ID
10.1.2 维度的基本设计方法
数据仓库的能力直接与维度属性的质量和深度成正比,维度设计方法:
第一步:选择维度或者新建维度,在数据仓库中要保证维度的唯一性,比如淘宝商品维度,有且只允许有一个维度定义。
第二步:确定主维表,一般主维表是ODS表,直接与业务系统同步。
第三部:确定相关维表, 根据对业务的梳理,确定哪些表和主维表存在关联,并选择其中的一些用来生成维度属性
第四步:确定维度属性,包括从主维表和相关维表中选择维度属性或生成新的维度属性
确定维度属性原则:
- 维度属性尽量丰富,为数据使用打下基础
- 给出详实的、富有意义的文字描述,可以给出ID和名称
- 区分数值型属性和事实。数值型字段是作为事实还是维度属性,可以参考字段的一般用途。 如果通常用于查询约束条件或分组统计,则是作为维度属性; 如果通常用于参与度量的计算, 则是作为事实。 如果数值型字段是离散值,则作为维度属性存在的可能性较大;如果数值型字段是连续值 ,则作为度量存在的可能性较大。
- 沉淀出通用的维度属性,为建立一致性维度做好铺垫,把那些比较复杂的逻辑处理的字段另外再放一个,再暴露出来。(好处:提高下游使用的方便性,减少复杂度;避免下游解析时由于逻辑不同而导致口径的不一致)
10.1.3 层次结构
维度中的一些描述属性以层次方式或者一对多的方式关联,可以理解为包含连续主从关系的属性层次。
在属性的层次结构中可以进行钻取,最底层代表最低级别的详细信息,最高的代表该要信息。
GMV(全称Gross Merchandise Volume),即商品交易总额。
10.1.4 规范化和反规范化
大多数OLTP的底层数据通过规范化处理将重复属性移至其自身所属的表中,删除冗余数据。这种方法可以有效避免数据冗余导致的不一致性。
比如在OLTP中的商品表和类目表,商品表和类目表是一对多的关系,且商品表中有冗余的类目表的属性字段。如果对某类目进行更新,可能要修改很多商品表,这个不太合理。在OLAP中数据是稳定的,不存在这个问题
维度的属性层次合并到单个维度的操作称为反规范化。
为什么要反规范化?
- 分析统计的主要目的是用于数据分析和统计。
- 采用雪花模型,在分析时需要大量的关联操作,复杂度高,查询性能慢
- 反规范化能简化模型,没有丢失信息,方便。
10.1.5 一致性维度和交叉探查
数据仓库总线架构的重要基石之一就是 一致性维度。
在针对不同数据域进行迭代构建或者并行构建时,需要将不同数据域的业务过程或者同一数据域的不同业务 合并在一起观察。
难点:
- 建设数据仓库不可能一蹴而就,采用迭代式构建过程
- 单独构建会造成独立型数据集市,导致严重的不一致性
维度不一致,会导致交叉探查出现问题,包括维度格式和内容的不同:
- 内容:日志数据域,商品维度为1 ;交易数据域,商品维度为2;商品维度1包含维度属性B,交易维度2不包含
- 格式:是时间属性格式yyyy-MM-dd HH:mm:ss,还有的是UNIX timestamp
维度一致性的表现形式
- 共享维表。如商品、买家等维度有且只有一个,基于这些公共维度进行的交叉探查不会有问题
- 一致性上卷。一个维度的维度属性是另一个维度的维度属性的子集,且两个维度的公共维度属性结构和内容相同。
- 交叉属性。两个维度具有部分相同的维度属性,与前面的那个类似。
10.2 维度设计高级
10.2.1 维度整合
数据仓库是一个面向主题的、集成的、 非易失的且随时间变化的的数据集合,用于对管理决策过程的支持。
集成是四个特性中最重要的。
整合的难点:
-
重要数据来源是大量、分散的,来自各种应用。应用很少会考虑到和其他系统的集成
-
应用在编码、命名习惯、度量单位等方面差异很大。如性别可以是1、0;F、M;
-
应用处于性能和扩展性考虑,物理实现方式不同。
所以要集成,需要做到:命名规范的统一、字段类型的统一、公共代码及代码值的统一、业务含义相同的表的统一(高内聚、低耦合)
整合的方式
- 采用主从表的设计方式,两个表都有字段放在主表(基本信息),从属的放在各自表中。主键采用复合主键、源主键和系统或表区别。
- 直接合并,公有和个性信息都在一起,重合度低时会出现大量空值
- 不合并,表结构及主键差异很大
垂直整合
- 垂直整合,不同的来源表包含相同的数据集,只是存储的信息不同。如淘宝会员在源系统中有很多表:会员基础信息表、扩展信息表、会员等级信息表,这些都属于会员相关信息表,尽量整合到会员维度模型中。
水平整合
- 水平整合,不同的来源表包含不同的数据集,同的数据集可能有交集可能没有。 如会员数据有淘宝会员、国际站会员、1688会员等。是否要整合到一个表中呢?如果要整合到一起,要考虑是是否有交叉?交叉的话要去重;不交叉的话,要考虑不同子集的自然键是否冲突。不冲突的话,可以将各个子集的自然键作为整合后的表的自然键;设置超自然键,将来源各子集的自然键加工成一个字段。(阿里通常采用将来源表各子集的自然键作为联合主键的方式,并在物理实现时将来源字段作为分区字段)
10.2.2 维度拆分
维度拆分的背景:
维度通常可以按照类别或者类型细分。比如淘系商品表,可以分为淘宝的商品、天猫商品、飞猪旅行商品。不同分类的商品,维度属性有相同点和不同点。比如航旅的商品和普通的商品,都有商品价格、标签等,但是航旅商品还有独特的属性维度(酒店、门票),如何设计维度呢?
维度设计的三个原则:
- 扩展性,源系统、业务逻辑变化时,能以较少的成本快速扩展模型,保持核心模型的相对稳定
- 效能,性能和成本平衡,一定的存储成本换性能和逻辑的优化
- 易用性,模型可理解性高,复杂性低
垂直拆分
需要考虑前面提到的三个原则,设计主从维度。主模型的稳定和产出时间的提前对数据仓库的稳定和下游应用的产出有重要意义。
主维表存放稳定、产出时间早、热度高的属性。 需要进行缓慢变化的处理
从维表存放变化较快、产出时间晚、热度低的属性。
水平拆分
需要考虑维度的不同分类的属性差异 和 业务的关联程度。
-
可以将维度的不同分类实例化为不同的维度,同时在主维度中保存公共属性,核心维度比较稳定
-
两个业务相关性比价低,耦合在一起弊大于利,如淘系商品和16888商品,属于不同的BU(业务单元),各自发展,一方修改还有一方要被迫修改。
10.2.3 历史归档
对于庞大的数据量,前端将商品状态为下架或者删除的且最近31天未更新的商品归档至历史库。数据仓库也可借鉴定期将历史数据归档至历史维表
策略一:同前台归档策略,定期对历史数据归档。 缺点:一、归档策略复杂,实现成本高;二、前台归档策略变化快,维护沟通成本高。适用于逻辑简单且变更不频繁的情况。
策略二:同前台归档策略,但是采用数据库变更日志的方式。通过数据库binlog日志解析获取每日增量,通过增量merge全量方式获取最新的全量数据。可以用增量日志的删除标志作为归档标志,前台应用中的删除只是逻辑删除
策略三:数据仓库自定义归档策略
10.3 维度变化
10.3.1 缓慢变化的维度
为什么要有缓慢变化的维度?
在数据仓库的重要特点之一是反映历史变化。现实世界中,维度的属性不是静态的,他会随着时间的流逝发生缓慢的变化(缓慢是和数据增长较快的事实表相比的)。当业务数据库中的一些数据发送了变化,如顾客的联系方式发生改变,一些基本信息的更改可能会引起数据归纳和分析出现的问题。
处理缓慢变化维的方式
方式一:重新维度值,不保留历史数据。
方式二:插入新的维度行,维度值变化钱的事实和过去的维度值关联
方式三:添加维度列,是由于方式二不能将变化前后记录的事实归一为变化前或者变化后的维度。
10.3.2 快照维表
Kimball的维度建模理论中,必须使用代理键作为每个维表的主键,用于处理缓慢变化维。但是在阿里并没有使用
为什么不使用代理键呢?
- 数据量庞大,且对于分布式系统来说,不存在事务的概念。对每个表记录生成稳定的全局唯一的代理键难度很大(稳定指某条记录每次生成的代理键都相同)
- 使用代理键会增加ETL复杂性,对开发和维度的成本很高。
如何解决缓慢变化维呢?
采用快照的方式,每天保留一份全量快照数据,通过限定日期采用自然键进行关联就可。优点:简单而高效、使用方便好理解。缺点:存储浪费
10.3.3 极限存储
用来解决存储浪费的问题
历史拉链存储
通过新增两个时间戳字段(start_dt和end_dt),将所有以天为粒度的变更数据都记录下来,通常分区字段也是时间戳字段。下游可以通过限制时间戳字段来获取历史数据,但是解释成本高,且存储方式用start_dt和end_dt做分区,时间推移分区数量膨胀。
极限存储(对历史拉链的优化)
一、透明化
底层还是历史拉链存储,上层做一个视图操作或者在hive里做一个hook,通过分析语句的语法树,转化查询。
select * from a where ds = 20211116
select * from a where start_dt <= 2021116 and end_dt > 20211116
二、分月做历史拉链
如果用start_dt和end_dt做分区,不做限制的话,一年最多可能产生的分区数是 365 x 364 / 2 = 66430。使用极限存储的话,可能产生的分区数:12 x (1 + (30+29)/ 2) = 5252。
|-- 202101/ # 每月一个周期
|----20210101/202101——INFINITY #每月1日的全量数据
|----20210101/20210102 #1月1日产生的1月2日死亡的数据
但是仍有缺点:
一、产出效率低,大部分极限存储通常需要t-2;
二、对于变化频率高的数据不能达到节约成本的效果。
对应的改进:
一、在极限存储前有一个全量存储表,全量存储表仅保留最近一段时间的全量分区数据,历史数据通过映射方式进行关联。
二、对于部分变化频率频繁的字段需要过滤。如用户积分字段每天在变化。不过滤的话,相当于每个分区存储一份全量数据,起不到节约存储成本的效果
10.3.4 微型模型
将一部分不稳定的属性从主维度中移出,并将他们放到拥有自己代理键的新表中来。这些属性互相之间没有直接关联,不存在自然键。
通过为每个组合创建新行的一次性过程来加载数据,比如VIP等级有8个值,用户信用等级有18个,那么在此微型维度中有8 x 18个组合,代理键可能是 1- 144。
优点:
可以解决维度的过度增长导致极限存储效果大打折扣的问题
缺点:
一、微型维度的局限性,事先用所有可能值的组合加载的,要考虑每个属性的基数且是枚举值。
二、ETL逻辑复杂,生成代理键和使用代理键加工都很复杂
三、破坏了维度的可浏览性,可能造成无法对应统计和未维护历史信息的问题
10.4 特殊维度
10.4.1 递归层次
指的是某维度的实例值的层次关系。按照层次是否固定分类均衡层次结构(地区,乡镇、曲线、城市、省份、国家)和非均衡层次结构(每个公司可能存在一个母公司,但没有固定的递归层次)
如何统计类目ID为1的最近一天GMV?
第一步:获取父类目ID为1的所有目录的所有类目,称为子类目。
第二步:每个子类目,如果为叶子类目,终止;如果不是叶子则继续往下找。
第三步:将所有叶子类目和交易事实表关联进行统计汇总。
很多的数据仓库系统不支持递归SQL,且成本较高。要对此层次结构进行处理
1.层次结构扁平化
通过建立维度的固定数量级别的属性来实现, 对于均衡层次结构,扁平化最有效。
如:类目 —— 类目名称 ——一级类目ID —— 二级类目ID —— 是否叶子类目。
每个类目保存一条记录,将其所属的各类目层级属性化。
如何统计呢?限制一级类目ID等于1之后进行汇总。
但是存在三个问题:
- 针对某类目上钻或者下钻之前,必须知道所属的类目层级
- 假设分三级类目统计最近一天的GMV,由于某些叶子类目直接是一级或二级目录,和交易事实表关联后,对应的三级类目为空,导致三级类目统计时(类目为10)的交易无法统计到。可以采用回填的方式,用的较多
- 扁平化仅包含固定数量的级别,对于非平衡层次结构可以通过预留级别的方式来解决,但扩展性差
2.层次桥接表
不需要预先知道层级,不用回填,也能解决非均衡层次问题,灵活性好。复杂性高,使用成本高(事实表和桥接表的多对多关系带来了双重计算的隐患)。
10.4.2 行为维度表
划分为以下几种
- 另一个维度的过去行为,如买家最近一次访问淘宝的时间
- 快照事实行为维度,如买家从年初截至当前的淘宝交易金额
- 分组事实行为维度,将数值型事实转化为枚举值,如买家信用分值按照分数划分得到的信用等级
- 复杂逻辑事实行为维度,通过算法加工或多个事实综合加工得到,如卖家主营类目
行为维度的处理方式
- 将其冗余至现在的维度表中,买家信誉等级冗余到买家表
- 加工成单独的行为表,如卖家主营类目
原则:
- 避免维度快速增长,将商品热度加入现有的维表中会导致极限存储效果差
- 避免耦合度过高,过多的业务耦合会导致维表刷新逻辑复杂、维护性差、产出延迟
10.4.3 多值维度
事实表的一条记录在某维表中有多条记录与之对应。比如一个订单,可能包含多个商品,交易父子订单。
常见的三种处理方式:
第一种:降低事实表的粒度,比如可以设置为子订单力度(商品力度)
第二种:采用多字段,比如房地产交易,有多个买受方。对于合同签订事实表,合同已经时此事实中最细力度了,可以用多字段的方式解决,有买受方一、买受方二。
第三种:使用桥接表,需要谨慎使用,可能带来双重计算的风险。
10.4.4 多值属性
维表中的某个属性字段同时有多个值,称为多值属性。如每个商品有一到多个SKU(Stock Keeping Unit 库存量单位)、属性(不同尺码、颜色分类)
常见的处理方式:
第一种:保持主键不变,将多值属性放在维度的一个属性字段中,用k-v对的形式保存。
第二种:保持主键不变,将多值属性放在维度的多个属性字段,比如卖家主营类目就是取的TOP3,可以固定数量。
第三种:维度主键发生变化,一个维度值存放多条记录,每个商品有多少SKU就有多少记录。数据容易膨胀
10.4.5 杂项维度
由操作系统中的指示符或者标志字段组合而成,不在一致性维度之列。
比如:交易订单的交易类型字段(话费充值、航旅);支付状态、物流状态;交易留言、交易属性(k-v对)、交易标签。
标签:存储,主键,商品,维度,设计,数据,类目,属性 来源: https://blog.csdn.net/qq_30031221/article/details/121362372