今天学习第 10 章维度设计。欢迎关注公众号回复 802 获取 pdf。
1.维度设计基础
1.1 维度的基本概念
- 维度是什么:度量-事实。环境-维度。维度就是分析事实所需要的环境。
- 维度做什么:维度属性是查询约束条件、分组和报表标签生成的基本来源,是数据易用性的关键。一般用来查询约束、分类汇总、排序。
- 维度的获取:报表中获取;与业务人员交流中发现;经常出现在 by 语句内。
- 维度用主键标识其唯一性。
1.2 维度的基本设计方法
以淘宝的商品维度为例:
- 选择或新建维度:保证维度的唯一性。比如商品维度,有且只有一个维度定义。
- 确定主维表:一般是 ODS 表,之间与业务系统同步。
- 确定相关维表:确定哪些表与主维表存在关系,选择其中某些表生成维度属性。例如商品维度,商品与类目、SPU、卖家、店铺等维度存在关系。
- 确定维度属性:首先从主维表中选择维度属性或生成新的维度属性;然后从相关维表中选择维度属性或生成新的维度属性。例如商品维度,从主维表,以及类目、SPU、卖家、店铺等相关维度中选择或生成维度属性。
确定维度的提示:
- 尽可能丰富
- 尽可能多给出富有意义的文字性描述,不应是编码,而是真正的文字
- 区分数值型属性和事实。数值型字段是事实还是维度,可以参考字段的一般用途。一般离散值是维度可能性大,连续值是事实可能性大。但不绝对。
- 通常用于查询约束条件或分组统计:维度属性;例如商品价格用于统计价格区间的商品数量,此时是维度。
- 通常用于度量:事实;例如商品价格用于统计某类目商品的平均价格,此时是事实。
- 尽量沉淀出通用的维度属性。有些维度属性的获取需要复杂的逻辑处理,或者通过多表关联,或者单表的不同字段混合处理,或者单表的某个字段解析。例如:商品是否在线,需要商品状态为 0 和 1 且商品上架时间小于等于当前时间,则是在线商品,否则是非在线商品。
1.3 维度的层次结构
维度中的一些描述属性有层次,例如商品属于类目,类目属于行业,类目中最低级的是叶子类目,叶子类目属于二级类目,二级类目属于一级类目。
通过向报表中添加连续的维度细节级别,实现在层次结构中钻取。
例如:
最高层:
钻取至行业:
钻取至一级类目:
1.4 规范化和反规范化
规范化:雪花模型,需要大量关联,查询性能差。
1.5 一致性维度和交叉探查
一致性维度:数据仓库总线架构的重要基石。
交叉探查:对不同数据域的业务过程,或统一数据域的不同业务过程,合并在一起观察,例如日志数据域统计了商品维度一天的 PV 和 UV,交易数据域统计了商品维度近一天的 GMV。将不同数据域的商品的事实合并在一起进行数据探查,比如计算转化率,称为交叉探查。
不同数据域重复的维度,其维度格式和内容不一致,会导致交叉探查无法进行。解决:
- 共享维表:例如商品、卖家、买家、类目等维度有且只有一个。
- 一致性上卷:其中一个维度的维度属性是另一个维度的维度属性的子集,且两个维度的公共维度属性结构和内容相同。例如:商品维度和类目维度,类目维度的属性是商品维度的属性的子集,这样基于类目交叉探查不会有问题。
- 交叉属性:两个维度部分维度属性相同。比如商品维度中有类目属性,卖家维度中有主营类目属性,可以在相同类目属性上进行不同业务过程的交叉探查。
2.维度设计高级主题
2.1 维度整合
内容:
- 命名规范统一:例如 uid 和 user_id
- 字段类型统一:相同和相似的字段类型统一
- 公共代码及代码值的统一
- 业务含义相同的表统一
形式:
- 垂直整合:不同来源,相同的数据集,存储的信息不同。比如淘宝会员下,有会员基础信息表、扩展信息表、等级信息表、天猫会员表,将其全表整合至会员维度模型中,丰富其维度属性。
- 水平整合:不同来源,不同的数据集,子集之间无交叉或部分交叉。例如蚂蚁金服的数仓采集了淘宝会员、1688 会员、支付宝会员。整合时,交叉的要去重;不交叉的考虑子集的自然键是否冲突,不冲突可以将各子集的自然键作为整合后的表的自然键,或设置超自然键。
2.2 水平拆分
问题:
维度通常可以按类别细分。例如商品都有价格、标题、类型、上架时间、类目,但航旅类商品还有独特的维度属性,比如酒店、景点、门票等都有子集独特的维度属性。
拆分的原则:
- 扩展性:业务、逻辑变化时能快速扩展,核心模型相对稳定。
- 效能:牺牲一定的存储成本,达到性能和逻辑的优化。
- 易用性:可理解性高,访问复杂度低。
拆分的依据:
- 依据维度的不同分类的属性差异情况。定义一个主维度存放公共属性,同时定义多个子维度,除了包括公共属性,还包括特殊属性。比如商品维度、航旅商品维度。公共属性保证核心维度的稳定性,扩展子维度的方式保证模型的扩展性。
- 依据业务的关联程度。关联性低的业务耦合在一起弊大于利。比如淘宝商品和 1688 商品,底层技术统一,但属于不同 BU,一般不会互相调用。
2.3 垂直拆分
问题:
- 某些维度属性来源产出时间早,某些时间晚;
- 某些维度热度高、使用频繁,某些较少使用;
- 某些维度属性经常变化,某些较稳定。
拆分的原则:同水平拆分。
拆分的方法:设计主从维度。
- 主维表存放稳定、产出时间早、热度高的属性;
- 从维表存放变化快、产出时间晚、热度地的属性。
2.4 历史归档
比如前台不再使用的历史数据。
策略:
- 同前台策略。问题:前台策略复杂,经常变化,沟通维护成本高。适用于前台归档策略简单、不频繁变化时。
- 同前台策略但采用数据库变更日志的方式。简单易行,但前台要求数据库的物理删除只有在归档时才执行,应用中的删除只是逻辑删除。
- 自定义归档策略。
3.维度变化
3.1 缓慢变化维
缓慢变化维是因为现实世界中,维度的属性不是静态的,会随着时间流逝缓慢变化。处理方法:
- 重写维度值:不保留历史,始终取最新数据。
- 插入新的维度行:保留历史数据,维度值变化前的事实和过去的维度值关联,维度值变化后的事实和当前的维度值关联。缺点:不能将变化前后的记录归一化。
- 添加维度列:事实可以归一化到新的或旧的维度。
3.2 快照维表
Kimball 的建模中必须使用代理键作为主键,处理缓慢变化维。但实践中未使用,因为分布式计算系统不存在事务,生成唯一全局代理键难度大,而且代理键增加 ETL 的复杂性。
实际使用快照处理缓慢变化维。例如每天存一份全量商品快照数据,作为商品维度。
优点:简单,方便,理解性好,开发维护成本低。
弊端:浪费存储。
3.3 极限存储
历史拉链存储:缓慢变化维的第二种处理方式。通过新增 start_dt 和 end_dt,将变更记录下来。
缺点:下游使用方理解障碍,数据分析师和前端人员不理解,有解释成本。采用 start_dt 和 end_dt 做分区,分区极度膨胀。
极限存储的做法:
- 透明化:底层还是拉链存储,上层做了视图或 Hive 里的 hook,对下游用户透明。
- 分月做历史拉链表:假如用 start_dt 和 end_dt 做分区,那么一年的分区最多 365 * 364 / 2 = 55430 个。如果每个月月初重新开始做历史拉链表,一年最多 12 * (1 + (30 + 29) / 2) = 5232 个。
极限存储能压缩存储成本,对下游透明。但产出效率低,通常要 t-2。变化频率高不能节约成本。额外处理:
- 极限存储前有一个全量存储表,保留最近一段时间的全量分区数据,历史数据通过映射关联到极限存储表。用户只访问全量存储表。
- 部分频繁变化的字段需要过滤。例如用户表中的积分。
3.4 微型维度
频繁变化的属性假如维度表,导致极限存储没有意义。将频繁变化的属性从维度表中移除,放置到全新的维表中。或使用垂直拆分,保证主维度的稳定性。或者使用微型维度。
原理:将不稳定的属性从主维度移除,放到拥有自己代理键的新表中。这些属性之间没有直接关系,不存在自然键。通过为每个组合创建新行的一次性过程来加载数据。比如用户维度,注册日期、性别、省份信息不变,VIP 等级、信用评价会变。假如 VIP 共 8 个值 -1~6,信用共 18 个值,那么微型维度共有 8 * 18 = 144 条记录。代理键 144 个。
4.特殊维度
4.1 递归层次
均衡层次:例如类目,叶子类目、三级类目、二级类目、一级类目;地区,乡镇/街道、区县、城市、省份、国家。
非均衡层次:公司之间,每个公司存在一个母公司,但没有一级、二级关系。
由于不支持递归 SQL,所以需要在维度模型中对此层次结构进行处理。
4.1.1层次结构扁平化
4.1.2 层次桥接表
类目树如下:
4.2 行为维度
定义:与事实相关,如交易、物流等,称为行为维度或事实衍生维度。比如用户常用地址维度,卖家主营品牌维度。都需要统计计算才能得到。
加工:
- 另一维度的过去行为,例如买家最近一次登录。
- 快照事实行为维度,如买家信用分。
- 分组事实行为维度,将数值型转换为枚举值,例如买家信用分数划分为等级。
- 复杂逻辑事实行为维度,例如商品热度,根据访问、收藏、加购、交易综合计算。
处理方式:冗余至维度表或单独加工成维度表。
4.3 多值维度
事实表的一条记录,在某维表中有多条记录与之对应。比如一次购买了多种商品。处理方式:
- 降低事实表的粒度:数仓中,关注子订单粒度,一个子订单只有一种商品。
- 多字段:比如买房,夫妻共同买,但合同已经是最细粒度无法拆分。可以预留字段:其他买方。
- 桥接表。事实表和维度表中开发一个分组表。例如刚刚的买房问题:
4.4 多值属性
例如每个商品下面,有一个或多个 SKU。处理方式:
- 保持维度主键不变,多值属性放在维度的一个属性字段中,该字段下通过 k-v 对存放。扩展性好,使用麻烦。
- 保持维度主键不变,多值属性放在维度的多个属性字段中。扩展性差,字段数量不固定。
- 维度主键变化,一个维度值存放多条记录。比如商品 SKU 维表,每个商品有多少个 SKU 就有多少记录,主键是商品 ID 和 SKU 的 ID。扩展性好,使用方便。
4.5 杂项维度
由操作型系统中的指示符或标志字段组合而成,不在一致性维度中。比如交易订单的交易类型字段,包括话费充值、司法拍卖等。