大数据:维度设计
目录:
- 维度设计基础
- 维度的基本概念
- 维度的基本设计方法
- 维度的层次结构
- 规范化和反规范化
- 一致性维度和交叉探查
- 维度设计高级主题
- 维度整合
- 水平拆分
- 垂直拆分
- 历史归档
- 维度变化
- 缓慢变化维
- 快照维表
- 极限存储
- 微型维度
- 特殊维度
- 递归层次
- 行为维度
- 多值维度
- 多值属性
- 杂项维度
- 数据岗位工作:了解需求 → 模型设计 → ETL 开发 → 测试 → 发不上线 → 日常运维 → 任务下线;
一、维度设计基础
1、维度的基本概念
- 维度的作用:一般是用来进行查询约束、分类汇总、排序等操作的;
- 维度建模从分析决策的需求出发构建模型;
- 维度是事实表的组成部分,是对事实表的扩展或进一步解释说明;
- 在维度建模中,将度量称为 “事实”,将环境描述为 “维度”,维度是用于分析事实所需要的多样环境;
- 例:在分析交易过程时,“淘宝交易事务事实表” 中的买家、卖家、商品、时间等维度,以这些维度建立的维表,来描述交易发生的环境,以及对 “淘宝交易事务事实表” 进一步解释说明;
- “淘宝交易事务事实表” 实例
- 维度属性:维度所包含的内容,为维度的列;
- 如:上图中的 “发货地区维度表” 中的区县、城市、省份、国家;
- 维度属性是查询约束条件、分组、报表标签生成的基本来源,是数据易用性的关键;
- 例1:在查询请求中,想获取某类目的商品、正常状态的商品等信息,是通过约束商品类目属性和商品状态属性来实现的(也就是设定商品类目属性、商品状态属性为查询条件,来查询获取目标信息);
- 例2:统计淘宝不同商品类目的每日成交金额,是通过商品维度的类目属性进行分组的;
1/1)如何获取维度或维度属性?
- 可以在报表中获取;
- 可以在和业务人员交谈中发现维度或维度属性;
- 因为维度或维度属性经常出现在查询或报表请求中的 “按照。。。” 语句中;
- 例:用户要 “按照” 月份和产品来查看销售情况;—— 那么用来描述其业务的自然方法应该作为维度或维度属性包括在维度模型中;
1/2)代理键、自然键
- 维度使用主键标识其唯一性,主键也是确保与之相连的任何事实表之间 存在引用完整性的基础;
- 主键有两种:代理键和自然键,都是用于标识某维度的具体值;
- 代理键是不具有业务含义的键,一般用于处理缓慢变化维;
- 自然键是具有业务含义的键;(自然键,一般就是维度在具体业务数据中的名称或 ID,而且名称或 ID 在一个业务模块中是独有的,没有跟它相同的)
- 例:上图 “淘宝交易事务事实表” 中的买家 ID、卖家 ID、商品 ID等,在业务过程中,都具有具体的含义;
- 对于前台应用系统来说,商品 ID 是代理键;对于数据仓库系统来说,商品 ID 属于自然键;
2、维度的基本设计方法
- 维度的设计过程就是确定维度属性的过程;
- 如,维度 “买家“,其设计过程,就是确定买家的姓名、性别、ID、籍贯等与之相关的信息,也就是其维度属性;
- 如何生成维度属性,以及所生成的维度属性的优劣,决定了维度使用的方便性,是数据仓库易用性的关键;
- Kimball:数据仓库的能力直接与维度属性的质量和深度成正比;
2/1)以淘宝的商品维度为例对维度设计方法进行说明:
- 第一步:选择维度或新建维度;
- 分析需求,选择维度或新建维度;
- 作为维度建模的核心,在企业级数据仓库中必须保证维度的唯一性;
- 例:淘宝商品维度,有且只允许有一个维度定义;
- 第二步:确定主维表;
- 此处的主维表一般是 ODS 表,直接与业务系统同步;
- 例:淘宝商品维度,s_auction_auctions 是与前台商品中心系统同步的商品表,此表即是主维表;
- 前端商品系统:为商城、购物车、订单、营销活动等提供商品基础数据支撑;
- 后端商品系统:为供应商管理、采购订单等提供数据支持;
- 第三步:确定相关维表;
- 数据仓库是业务源系统的数据整合,不同业务系统或者同一业务系统中的表之间存在关联性;
- 根据对业务的梳理,确定哪些表和主维表存在关联关系,并选择其中的某些表用于生产维表属性;
- 例:淘宝商品维度,梳理业务逻辑,可以得到商品与类目、SPU、卖家、店铺等维度存在关联关系;
- 第四步:确定维度属性;
- 第一阶段:从主维表中选择维度属性或生成新的维度属性;
- 第二阶段:从相关维表中选择维度属性或生成新的维度属性;
- 例:淘宝商品维度,从主维表(s_auction_auctions)和相关维表(类目、SPU、卖家、店铺等)中选择维度属性或生成新的维度属性;
- 确定维度属性注意事项:
- 尽可能生成丰富的维度属性;(唯一维度尽量囊括所有相关的维度属性)
- 如淘宝的商品维度有近百个维度属性,为下游的数据统计、分析、探查提供了良好的基础;
- 尽可能多的给出包括一些富有意义的文字性描述;(便于大家理解属性所指的意思)
- 属性不应该是编码,而应该是真正的文字;
- 在阿里的维度建模中,一般是编码和文字同时存在,如商品维度中的商品 ID、商品标题、类目 ID、类目名称等;
- ID 一般用于不同表之间的关联,而名称一般用于报表标签;
- 区分数值型属性和事实;(有的数值是指代,比如 0 、1,有时并不是数值 0 和 1)
- 如果通常用于查询约束条件或分组统计,数值型字段是作为维度属性;
- 如果通常用于参与度量的计算,数值型字段则是作为事实;
- 有时即可作为维度属性使用,由可以作为事实用用:如商品价格,如果用于统计价格区间的商品数,是作为维度属性使用;如果用于统计某类目下商品平均价格,则是作为事实使用;
- 另外,如果数值型字段是离散的,则作为维度属性存在的可能性较大;如果数值型字段是连续的,则作为度量存在的可能性较大,但是不绝对;
- 尽量沉淀出通用的维度属性;(便于大家相互理解)
- 一方面,提高下游使用的方便性,减少复杂性;
- 另一方面:避免下游使用解析时,由于各自逻辑不同而导致口径不一致;
- 尽可能生成丰富的维度属性;(唯一维度尽量囊括所有相关的维度属性)
3、维度的层次结构
- 如果维度中的描述属性,以层次方式或一对多的方式相互关联,可以被理解为包含连续主从关系的属性层次;
- 层次的最底层,代表维度中描述最低级别的详细信息;层次的最高层,代表最高级别的概要信息;
- 例:淘宝商品维度,有卖家、类目、品牌等,商品属于类目,类目属于行业;其中类目的最低级别是叶子类目,叶子类目属于二级类目,二级类目属于一级类目;
- 在属性的层次结构中进行钻取,是数据钻取的方法之一;
- 例:假设已有一个淘宝交易订单,创建事实表;
- 方法:通过向报表中添加连续的维度细节阶级,实现在层次结构中钻取;
- 统计 2015 年 “双 11 ”的下单 GMV(所有订单的总金额,包括已付款的和未付款的),得到一行记录;
- 沿着层次向下钻取,添加行业,得到行业实例的记录数;
- 沿着层次向下钻取,添加一级类目,得到一级类目实例个数的记录;
4、规范化和反规范化
- 雪花模式:当属性层次被实例化一系列维度,而不是单一的维度时,被称为雪花模式;
- 理解,就是以主维度的属性为维度,建立一些列子维维;(如,下图 10.1 所示)
- 规范化操作:将属性层次实例化为一系列维度,而不是单一维度,称为规范化操作(也即为雪花模式);(产生多个相关联的表)
- 反规范化操作:将维度的属性层次合并到单个维度中的操作,称为范规范化;(将多个相关联的表整合到一起)
- SPU:标准化商品单元;
- SKU:库存量单元;
- 例:手机,买的一个纸盒包装好的标配手机,就是一个 SPU;一个 SKU 可能包含若干个 SPU,比如仓库里一箱(具体要看仓库中最小存储单元是什么)有 20 个手机;
- 例1:雪花模式;
- 例2:反规范化操作;
- 雪花模式的劣势:
- 更新不便:如例 1,如果更新商品表,则需要更新与之相关联的所有表;
- 查询不便:如例 1,如果查询某具体的商品的详细信息,则需要查询与之关联的所有表中与其有关的信息,然后再整合到一起,需要大量的关联操作;
- 雪花模式的优点:节约存储空间;
- 反规范化操作的优点:复杂度低,便于查询与更新;
- 大多数联机事务处理系统(OLTP)的底层数据结构,在设计时采用雪花模式技术,通过规范化处理将重复属性移至其自身所属的表中,删除冗余数据;
5、一致性维度和交叉探查
5/1)交叉探查
- 定义:将不同数据域的商品的事实合并在一起进行数据探查,如计算转化率等,称为交叉探查;(两个数据域叫的实时放一起分析)
- 能够进行交叉探查的条件:进行交叉探查的两个维度属性(隶属于两个维度),必须相同,且属性值的格式也一致;
- Kimball 构建企业级数据仓库方法:通过构建企业范围内一致性维度和事实,来构建总线架构;
- 一致性维度,是数据仓库总线架构的重要基石之一;
- 在针对不同数据域进行迭代构建或并行构建时,存在很多需求,是对不同数据域的业务过程,或者同一数据域的不同业务过程,合并在一起观察;
- 例:对于日志数据域,统计了商品维度的最近一天的 PV 和 UV;对于交易数据域,统计了商品维度的最近一天的下单 GMV;如果要对两个数据域并行构建,则需要将PV、UV、GMV 合并在一起进行数据探查;
5/2)一致性维度
- 不同数据域的维度不一致,不能进行交叉探查;
- 维度不一致:维度属性不一致、维度属性一致但维度属性的值的格式不一致、维度属性及其值的格式都不一致(如维度属性时间:yy-MM-dd、UNIX timestamp,格式不一致);
- 情景:假设对于日志数据域,统计使用的是商品维度 1;对于交易数据域,统计使用的是商品维度 2;
- 维度属性不一致:商品维度 1 包含维度属性 BC 类型,而商品维度 2 无此属性,则无法在 BC 类型上进行交叉探查;
- 维度属性移至但属性值不一致:商品维度 1 的商品上架时间,这一维度属性的时间格式是 yyy-MM-dd HH : mm : ss,商品维度 2 的商品上架时间这一维度属性的时间格式是 UNIX timestamp,进行交叉探查时,如果需要根据商品上架时间做限制,则复杂性较高;
- 维度一致性的几种表现形式:
- 共享维表;
- 如,阿里的数据仓库中,商品、卖家、买家、类目等维度有且只有一个,在基于这些公共维度进行的交叉探查不会存在问题;
- 一致性上卷:一个维度的维度属性,是另一个维度的维度属性的子集,且两个维度的公共维度属性结构和内容相同;
- 如,阿里的商品体系中,有商品维度和类目维度,其中类目维度的维度属性是商品维度的维度属性的子集,且有相同的维度属性和维度维护性值,这样基于类目维度进行不同业务过程的交叉探查不会存在问题;
- 交叉属性:像个维度具有部分相同的维度属性;
- 如,在商品维度中具有类目属性,在卖家维度中具有主营类目属性,两个维度具有相同的类目属性,则可以在相同的类目属性上进行不同业务过程的交叉探查;
- 共享维表;
二、维度设计的高级主题
1、维度整合
- 数据仓库定义:是一个面向主题的、集成的、非易失的、随时间变化的数据集合,用来支持管理人员的决策;
- 集成性是数据仓库四大特性中最重要的一个;
- 主题:不同的应用环境,或者不同的业务模块;
- 数据仓库的重要数据来源,是大量的、分散的、面向应用的操作型环境;
- 不同的应用在设计过程中,可以自由决策,主要满足本应用的需求,很少会考虑和其他系统进行数据集成;
1/1)应用间的差异表现在如下几个方面
- 应用在编码、命名习惯、度量单位等方面存在很大差异;
- 如,不同应用对性别编码不同:有 0 和 1、有 F 和 M 等;
- 如,不同应用的用户 ID 含义相同,但字段名称不同:user、user_id 等;
- 如,不同应用对于金额的度量单位不同:元、分等;
- 应用出于性能和扩展性的考虑,或者随技术架构的演变,以及业务的发展,采用不同的物理实现;拆分至不同类型数据库中,部分数据采用关系型数据库(如 Oracle、MySQL 等),部分数据采用 NoSQL 数据库存储(如 HBase、Tair 等);拆分成同一类型数据库中的多个物理表;
- 如,淘宝商品,有商品主表和商品扩展表,商品主表存储商品基本信息,商品扩展表存储商品特殊信息,如不同产品线的定制化信息等;
- 如,淘宝会员,有会员主表和会员扩展表,会员主表存储用户基本信息,会员扩展表存储用户扩展信息,如用户的各种标签信息等;
1/2)数据集成
- 由于应用间的差异,数据有面向应用的操作型环境进入数据仓库后,需要进行数据集成;
- 将面向应用的数据,转换为面向主题的数据仓库数据,本身就是一种集成,具体体现在日下几个方面:
- 制作单张表时规范统一(如下 1、2、3 方面)、在整合多张表时规范统一(如下 第 4 方面);
- 名规范的统一:表名、字段名等统一;
- 字段类型统一:相同和相识字段的字段类型统一;
- 公共代码及代码值的统一:公共代码及标志性字段的数据类型、命名方式等统一;
- 业务含义相同的表的统一
- 高内聚、低耦合理念:将业务关系大、源系统影响差异小的表进行整合;将业务关系小、源系统影响差异大的表进行分而置之;
- 制作单张表时规范统一(如下 1、2、3 方面)、在整合多张表时规范统一(如下 第 4 方面);
-
常用集成方法:
- 采用主从表的设计方式
- 将两个表或多个表都有的字段放在主表中(主要基本信息),从属信息分别放在各自的从表中;
- 对于主表中的主键,要么采用复合主键、源主键和系统或表区别标志,要么采用唯一主键、“源主键或表区别标志” 生成新的主键;通常采用复合主键;
- 直接合并:共有信息和个性信息都放在同一个表中;
- 注意:如果表字段的重合度较低,则会出新大量空值,对于存储和易用性有影响,需谨慎选择;
- 不合并
- 源表的结构及主键差异很大,无法合并,使用数据仓库的多个表存放各自的数据;
1/3)表级别的整合
- 表级别的整合,有两种表现形式:
- 第一种是垂直整合:不同的来源表包含相同的数据集,只是存储的信息不同;
- 如,淘宝会员在源系统中有多个表,会员基础信息表、会员扩展信息表、淘宝会员等级信息表、天猫会员等级信息表,这些表都属于会员的相关信息表,依据维度设计方法,尽量整合至会员维度模型中,丰富维度属性;
- 第二种是水平整合:不同的来源表包含不同的数据集,不同子集之间无交叉,也可以存着部分交叉;
- 如,蚂蚁金服的数据仓库,其采集的会员数据有淘宝会员、1688 会员、国际站会员、支付宝会员等,是否需要将所有的会员整合到一个会员表中?如果进行整合:
- 如果各个会员体系有交叉,需要去重;
- 如果各个会员体系没有交叉,需要考虑不同子集的自然键是否存在冲突,如果不冲突,则可以考虑将各子集的自然键作为整合后的表的自然键;或者,设置超自然键,将来源表各子集的自然键加工成一个字段作为超自然键;(在阿里,通常采用将来源表各子集的自然键作为联合主键的方式,并且在物理实现时将来源字段作为分区字段。)
- 如,蚂蚁金服的数据仓库,其采集的会员数据有淘宝会员、1688 会员、国际站会员、支付宝会员等,是否需要将所有的会员整合到一个会员表中?如果进行整合:
- 第一种是垂直整合:不同的来源表包含相同的数据集,只是存储的信息不同;
2、水平拆分
2/1)维表分析
- 维度通常可以按照类别或类型进行细分:
- 情景 1:淘系商品表,根据业务线或行业可以对商品细分:淘宝商品、天猫商品、1688 商品、飞猪旅行商品、淘宝海外商品、天猫国家商品等;
- 不同分类的商品,其维度属性可能相同,也可能不同:
- 情景 2:航旅的商品和普通淘系商品,都属于商品,都有商品价格、标题、类型、上架时间、类目等维度属性,但是航旅的商品除了公共属性,还有酒店、景点、门票、履行等自己独特的维度属性;
2/2)如何设计维度
- 思路:根据上述分析的维表数据情景,反向思考维度设计方案;
- 方案一:将维度的不同分类实例化为不同的维度,在主维度中保存公共属性,在扩展子维度中存放独特的维度属性;
- 方案二:维护单一维度,包含所有可能的属性;
- 维度设计考虑原则:
- 扩展性:当源系统、业务逻辑变化时,能通过较少的成本快速扩展模型,保持核心模型的相对稳定性;(高内聚、低耦合为重要指导思想;)
- 效能:在性能和成本方面取得平衡;(通过牺牲一定的存储成本,达到性能和逻辑的优化)
- 易用性:模型可理解性高、访问复杂度低;(方便用户从模型中进行数据查询和分析)
2/3)如何拆分维度
- 思路:根据上述维度设计的过程,反向思考维度拆分依据;
- 维度的不同分类的属性的差异情况;(有些属性相同或相识,有些维度差异很大)
- 定义一个主维度存放公共属性、定义多个子维度存放公共属性和各自的独特属性;
- 业务的关联程度;
- 两个相关性较低的业务,分别建立维度;
- 相关性较低的业务:具有各自的数据集市,一般不相互调用,业务分析人员一般只针对本数据集市进行统计分析;
3、垂直拆分
- 维度属性的丰富程度决定了数据仓库的能力;
- 能力:快速组织和存储数据、快速查询和分析数据
- 出于扩展性、产出时间、易用性等方面考虑,设计主从维度:主维表存放稳定、产出时间早、热度高的属性,从维表存放变化较快、产出时间晚、热度低的属性;
- 由于商品有扩展冗余的库存等变化较快的数据,对于主维度进行缓慢变化的处理较为重要;
- 通过存储的冗余和计算成本的增加,实现了商品主模型的稳定和产出时间的提前,对于整个数据仓库的稳定和下游应用的产出都有较大意义;
4、历史归档
- 归档:将历史数据归档至历史维表中;
- 前台归档方法:如,将商品状态为下架或删除的、且最近 31 天内未更新的商品,归档至历史库;具体逻辑根据不同 BU,有不同的算法,且有特殊的规则;
-
数据仓库中的归档策略:
- 归档策略 1:同前台归档策略,在数据仓库中实现前台归档算法,定期对历史数据进行归档;
- 问题 1:前台归档策略复杂,实现成本较高;
-
问题 2:前台归档策略坑能会经常变化,导致数据仓库归档算法也要随之变化,维护和沟通成本较高;
-
总结:此方案使用于前台归档策略逻辑较为简单,且变更不频繁的情况;
- 归档策略 2:同前台归档策略,但采用数据库变更日志的方式;
-
通过数据库 binlog 日志解析获取每日增量;
-
通过增量的 merge 全量的方式获取最新的全量数据;
-
使用增量日志的删除标志,作为前台数据归档的标志,通过此标志对数据仓库的数据进行归档;
-
总结:不需要关注前台归档策略,简单异性,但对前台应用的要求是,数据库的物理删除只有在归档时才执行,应用中的删除只是逻辑删除;
-
- 归档策略 3:数据仓库自定义归档策略;
- 将归档算法用简单直接的方式实现,但要尽量比前台应用归档晚、少归档,避免出现数据仓库中已经归档的数据再次更新的情况;
- 归档策略 1:同前台归档策略,在数据仓库中实现前台归档算法,定期对历史数据进行归档;
- 归档策略总结:如果技术允许,能够解析数据库 binlog 日志,使用归档策略 2,规避前台归档算法;
三、维度变化
1、缓慢变化维
- 背景:现实世界中,维度的属性并不是静态的,会随着时间的流逝发生缓慢变化(如,VIP / 信誉 等级);(指属性值的变化)
-
处理缓慢变化维的 3 种方式(由 Kimball 提出):
- 实例进行说明:商品所属的类目于 2015 年 11 月 16 日,由类目 1 变成类目 2:
-
方式 1:重写维度值;
- 特点:不保留历史数据,始终取最新数据;
-
方式 2:插入新的维度行
-
特点:保留历史数据,维度值变化前的事实和过去的维度值关联,纬度值变化后的事实和当前的纬度值关联;
-
问题:不能将变化前后记录的事实,归一为变化前的维度或者归一为变化后的维度;
-
解释:因为插入新的维度行,相当于给维表添加新的商品,与维度属性变化前的商品,算做两种商品,那么事实表中也会添加新种类商品的数据;其实 “两种“ 商品只是某一属性或某几个属性不一样而已,其它属性完全一样,如果想对 “两种” 商品的历史数据进行统一统计时,此方法不便实现;
-
- 方式 3:添加维度列;
- 总结:选择哪种方式处理缓慢变化维,要根据业务需求进行选择;
2、快照维表
- Kimball 的维度建模理论中,必须使用代理键作为每个维表的主键,用于处理缓慢变化维;
2/1)阿里内部采用维度建模,但不使用代理键:
- 分布式计算系统 MaxCompute,生成稳定的、全局唯一的代理键的难度较大;
- 此处的稳定指,某条记录每次生成的代理键都相同;
- 使用代理键会大大增加 ETL 的复杂性,对 ETL 任务的开发和维护成本很高;
2/2)不使用代理键处理缓慢变化维
- 采用快照方式,处理缓慢变化维;
- 操作方式:
- 以数据仓库计算周期为频率,保留一份每一周期内的全量快照数据;(全量快照数据是按全量存储方式存储的)
- 限定日期,任意周期的事实快照和维度快照通过维度的自然键进行关联;
-
例:商品维度;
- 每天保留一份全量商品快照数据,任意一天的事实均可获取到当天的商品信息,也可以获取到最新的商品信息,通过限定日期,采用自然键进行关联即可;
-
优点:
- 简单有效,开发和维护成本低;
- 使用方便,理解性好;(数据的使用方只需要限定日期,即可获取当天的快照数据,任意一天的事实快照与维度快照,通过维度的自然键进行关联即可)
- 弊端:极大浪费存储;
- 总结:此方法就是牺牲存储获取 ETL 效率的优化和逻辑上的简化;但是,杜绝过度使用此方法,而且必须要限定数据的生命周期,清除无用的历史数据;
3、极限存储
3/1)历史拉链存储
- 思想:在每个数据仓库计算周期内,只记录变化的数据,对于不变的数据不再重复记录;
- 历史拉链存储:利用维度模型中缓慢变化维的第二种处理方式;(插入新的维度行)
- 操作方式:新增两个时间戳字段( start_dt 和 end_dt ),将所有以天为粒度(数据仓库计算周期)的变更数据,都记录下来;
- 通常分区字段也是时间戳字段;
- 例:2016 年 1 月 1 日,卖家 A 在淘宝上发布了 B、C 两个商品,前端商品表将生产两条记录 t1、t2;1 月 2 日,卖家 A 将 B 商品下架了,同时发布了商品 D ,前端商品表将更新记录 t1,有新生成记录 t3;
- 采用全量存储方式:在 1 月 1 日分区中存储 t1、t2 两条记录;在 1 月 2 日分区中存储更新后的 t1、t2、t3 记录;
- 采用历史拉链存储:对于不变的数据,不再重复存储;
- 下游应用只需要限制时间戳字段来获取历史数据;(例:用户访问 1 月 1 日的数据:start_dt <= 20160101 和 end_dt > 20160101 )
- 采用全量存储方式:在 1 月 1 日分区中存储 t1、t2 两条记录;在 1 月 2 日分区中存储更新后的 t1、t2、t3 记录;
-
历史拉链存储弊端:
- 不变下游工作人员理解;(特别是 ODS 数据面向的下游用户,包括数据分析师、前端开发人员等;他们不怎么理解数据模型的概念)
- 使用 start_dt 和 end_dt 做分区,随着时间的推移,分区数量会越来越多,而现行的数据库系统都有分区数量限制;
3/2)极限存储
- 在历史拉链存储的基础上完善,步骤:
- 透明化
- 底层的数据使用历史拉链存储方式;
- 在上层做一个视图操作,或者在 Hive 里做一个 hook;
- 视图操作 / hook 的目的:通过分析语句的语法树,把对极限存储前的表(历史历练表在一个周期的初期,也就是拉链存储周期第一天的全量数据)的查询,转换成对极限存储表的查询;
- 极限存储表:一个拉链存储周期内,历史拉链存储方式存储的数据;
- 极限存储前的表:一个拉链周期初始时的全量数据;
- 对于下游用户来说,极限存储表和全量存储方式是一样的:
- 例:查询 20160101 的数据;
- 视图操作 / hook 的目的:通过分析语句的语法树,把对极限存储前的表(历史历练表在一个周期的初期,也就是拉链存储周期第一天的全量数据)的查询,转换成对极限存储表的查询;
- 做历史拉链表:按周期记录变化的数据;
- 设置历史拉链表周期;
- 假设以 start_dt 和 end_dt 做分区,每月月初重新做历史拉链表,则表的结构为:
-
1 天为最小分区区间,31 天最长分区区间,1 个月中可能有:30 x 31 / 2 = 465 个分区;(则一年最多可能产生的分区数:465 x 12 = 5580 )
-
1002 产生且 1003 死亡记录:采用历史拉链存储方式,从第 2 天到第 3 天的存储数据;
-
1001 产生且 1031 死亡记录:采用历史拉链存储方式,从第 1 天到第 31 天的存储数据;
-
疑问:每月 1 日的全量数据是什么?
-
- 对极限存储做额外处理:
-
在做极限存储前有一个全量存储表,仅保留最近一段时间的全量分区数据,历史数据通过映射方式关联到极限存储表;(用户只访问全量存储表,通过映射,关联到极限存储表,得到最新的变更的全量数据;)(极限存储表对用户是不可见的)
-
对变化频率较高的字段需要过滤;
- 方法一:垂直拆分维度,主维表 + 子维表;
- 方法二:创建微型维度,主维表 + 子维表;
-
- 极限存储方式的优点:即压缩了存储成本,又达到对下游用户透明的效果;
- 极限存储方式的弊端:
- 产出效率很低:大部分极限存储通常需要 t-2;
- 对于变化频率高的数据,不能达到节约成本的效果;
4、微型维度
4/1)创建微型维表
- 作用:对极限维度的完善;(处理被过滤出的高频字段)
- 创建微型维度:将一部分不稳定的属性从主维度中移出,放置到拥有自己代理键的新表中,这个新表就是微型维表;
- 微型维表的数据:所有属性的可能值的排列组合,是固定的数据;(并不是记录每次属性的变化值)
- 例:用户 VIP 等级和用户信用评价等级,会随着用户行为不断变化。其中,VIP等级共有 0 ~ 8,9 个值;信用等级有 10 个值。假设基于 VIP 等级和用户信用等级构建微型维度,则在微型维度中共有 9 x 10 个组合,即 90 条记录,代理键可能是 1~90;
- 微型维度中,属性间没有直接关联,不存在自然键,只能使用代理键;
- 例:淘宝交易事实表,其它维度忽略,星形模式可能表示如下图;
4/2)阿里数据仓库不使用微型维度技术
- 微型维度的局限性;
- 微型维度是事先用所有可能值的组合加载的,需要考虑每个属性的基数,且必须是枚举类型;但很多属性可能是非枚举类型,比如数值类型,如 VIP 分数、信用分数等;时间类型,如上架时间、下架时间、变更时间等;
- ETL 逻辑复杂;
- 对于分布式系统,生成代理键和使用代理键进行 ETL 加工都非常复杂,ETL 开发和维护成本过高;
- 破坏了维度的可浏览性;
- 如,买家维度和微型维度通过事实表建立联系,无法基于 VIP 等级、信用等级进行浏览和统计。(可以在买家维度中添加引用微型维度的外键来解决,但带来的问题是微型维度未维护历史信息;)
四、特殊维度
1、递归层次
- 递归层次:维度属性以层次方式或一对多的方式相互关联;
- 例:典型的就是商店的商品分类表,一层层的向下细分;(蔬菜水果 → 蔬菜 → 叶菜类 / 根茎类 / 茄夹类)
- 维度的递归层次,按照层级是否固定,分为均衡层次结构和非均衡层次结构;
- 均衡层次结构:层级固定;(如,地区,有固定数量的级别 —— 国家、省份、城市、区县、乡镇 / 街道,并且级别间的关系是固定的)
- 非均衡层次机构:层级不固定;(如,公司之间的关系,每个公司可能存在一个母公司,但可能没有固定的一级、二级等层次关系;)
- 例:淘宝交易事实表通过叶子类目和类目维表关联,统一类目 ID 为 21 的最近一天的 GMV:
- 获取父类目 ID 为 21 的所有类目,称为子类目;
- 判断子类目是否为叶子类目,如果是叶子类目,则终止;如果不是,以此类目 ID 为父类目 ID,执行第一步操作,知道找到所有的叶子类目;(需要递归查找)
- 将所有叶子类目和交易事实表关联,进行统计汇总,即可得到类目 ID 为 21 的最近一天的 GMV;
-
业务难题:由于很多数据仓库系统和商业智能工具不支持递归 SQL,并且用户使用递归 SQL 的成本较高,所以在维度模型中,需要对递归层次结构进行处理:
1/1)层次结构扁平化
- 目的:降低递归层次使用复杂度;
- 扁平化操作:建立维度的固定数量级别的属性;(也就是列举出所有的层级)
- 如果高层级类目下没有低层级类目,也就是其本身是叶子类目,则低层级类目置为空值;
- 使用于均衡层次结构;(均衡层次结构层级固定)
- 例:淘宝商品类目,扁平化操作后如下图:
- 需求:统计类目 ID 为 21 的最近一天的 GMV;
- 将淘宝交易事实表,通过叶子类目和类目维表(扁平化后的类目维表)的类目 ID 关联,限制一级类目 ID 等于 21,之后进行汇总统计;
-
层次结构扁平化过程中需要解决的问题:
- 针对某类目上钻或下钻之前,必须知道其所属的类目层级,才能决定限制哪一级别类目;(如,类目 ID 等于 21,需要先知道其为哪一级别的类目,才能在关联时进行限定)
- 如果分五级类目,而有些叶子类目直接是一级类目或二级类目,其后面的为空值,如果限定三级类目统计 GMV,和交易事实表关联后,这些叶子类目为一级或二级类目的交易无法被统计到;
- 扁平化仅包含固定数量的级别,对于非平衡层次结构,可以通过预留级别的方式来解决,但扩展性较差;
-
解决方法:
- 在进行数据统计前,在类目层级结构扁平化时,对空值进行回填,将类目向下虚拟;(例:如下图)
1/2)层次桥接表
-
层次桥接表:
- 从高层到底层,以所有层次的属性作为父类,以与父类本身和比父类低层级的类,作为子类目;(不能用与父类同层级或者比父类层级高的类做子类)
-
例:
- 数据存储实例:
-
-
桥接表:
- 类目层级间隔:父类目与其子类间的层级差;
-
解决的问题:
- 不需要预先知道所属层级、不需要回填、可解决非均衡层次结构;
- 步骤:
- 建立层级树;
- 根据层级树建立层次桥接表;
- 例 1:对类目 21 进行下钻操作
- 限制类目表的类目 ID 等于 21 ,通过类目 ID 和类目桥接表的父类目 ID 关联,使两表建立连接;(得到部分类目桥接表:类目 21所在层级及其以下所有的类目桥接表)
- 通过类目桥接表(步骤 1 得到的类目桥接表)的子类目 ID 和事实表的类目 ID 关联,使两表建立连接;
- 例 2:对类目 50026579 进行上钻操作
- 限制类目表的类目 ID 等于 50026579,通过类目 ID 和类目桥接表的子类目 ID 关联,使量表建立连接;
- 通过类目桥接表的父类目 ID 关联,使量表建立连接;
- 弊端:加工逻辑复杂,使用逻辑复杂,而且由于桥接表和事实表的多对多关系,有双重计算的隐患;
2、行为维度
2/1)定义
- 行为维度 / 事实衍生维度:通过从从事实中分析得到的维度;(常用到的词有:主营、主要、常用等)
- 例:
- 卖家主营品牌:需要从卖家的商品分布和交易情况中,分析得出一个卖家的主营品牌;
- 用户常用地址:需要从卖家发货地址和买家收货地址中,分析得到一个买家 / 用户经常使用的地址是什么;
2/2)分类
- 另一维度的过去行为
- 如,买家最近一次访问淘宝的时间、买家最近一次发生淘宝交易的时间等;
- 快照事实行为维度
- 如,买家从年初截止当前的淘宝交易金额、买家信用分值、卖家信用分值等;
- 分组事实行为维度,将数值型事实转换为枚举值
- 如,买家从年初截至当前的淘宝交易金额按照金额划分的等级、买家信用分值按照分数划分得到的信用等级;
- 复杂逻辑事实行为维度,通过复杂算法加工或多个事实综合加工得到;
- 如,卖家主营类目,商品热度根据访问、收藏、加入购物车、交易等情况综合计算得到;
2/3)处理行为维度的方式
- 方式 1:将行为维度冗余至现有的维表中;
- 如,将卖家信用等级冗余到卖家维表中;
- 方式 2:加工成单独的行为维表;
- 如,卖家主营类目,作为单独的行为维表;
2/4)处理行为维度遵循的原则
- 原则 1:避免维度过快增长;
- 如,对商品表进行了极限存储,如果将商品热度加入到现有的商品维表中,由于商品热度属性变更频道较高,可能会使每日商品变更占比过高,从而导致极限存储效果差;
- 原则 2:避免耦合度过高;
- 如,卖家主营类目,加工逻辑异常复杂,如果融合进现有的卖家维度中,那么过多的业务耦合会导致卖家维表刷新逻辑复杂、维护性差、产出延迟;
3、多值维度
3/1)什么是多为维度
- 对于多只维度,一种情况是,事实表的一条记录在某维表中有多条记录与之对应;
- 如,淘宝交易订单,买家一次购买了多种商品;
- 一次购买交易,作为交易父订单;
- 对于一次交易中的所有商品的购买,称为交易子订单;
- 设计交易父订单时,对于此事实表的每一条记录,在商品表中都有一到多条记录与之对应;
- 如,淘宝交易订单,买家一次购买了多种商品;
3/2)3 种方式处理多只维度
- 根据业务的表现形式和统计分析需求进行选择;
- 方式 1:降低事实表粒度
- 适用场景:行为事实可拆分;
- 如,淘宝交易中,前台业务和商业智能关注的是交易子订单;
- 那么在数据仓库模型设计中,要将交易设计为子订单粒度,对于每个子订单,只有一种商品与之对应;
- 对于事实,将交易数据分摊到子订单;
- 方式 2:采用多字段
- 适用场景:行为事实不可拆分;
- 如,房产销售,合同签订时可能有多个买方,如夫妻合买;
- 一条合同记录对应多个买方,而合同未事实中的最细粒度;
- 一般合同的买方不会太多,所以可采用多字段方式;
- 考虑到扩展性(以防可能追加多个买方),可以预留字段;
- 方式 3:采用通用的桥接表
- 场景:所有多值维度情况;
- 操作:在事实表和维表之间开发一个分组表,通过此分组表建立连接;
- 分组 KEY:用于关联事实表,以及作为买受方维表外键的买受方 ID;
- 如果事实表的一条记录对应 2 各受买方,则桥接表对这 2 各受买方建立两条记录,分组 KEY 相同;
-
双重计算风险:
- 双重计算不一定是错误,要根据业务需求情况而定;
- 例:需求——根据买方籍贯统计某一年的合同总金额;
- 如果两个买受方的籍贯分别杭州和苏州,那么此合同的总金额将会被分别到杭州和苏州,造成双重计算;
4、多值属性
4/1)什么是多值属性
- 多值属性:维表中的某个属性同时有多个值;
- 多值属性是多值维度的另一种表现形式;
- 例:商品 SKU 维表(一般就是指库存)、商品属性维表、商品表桥维表等;
- 每个商品均有一到多个 SKU、一到多个属性和一到多个标签,所有商品和 SKU、属性、标签都是多对多的关系;
4/2)3 种方式处理多种属性
-
根据具体情况进行选择:
- 方式 1:保留维度主键不变,将多值属性放在维度的一个属性字段中;(通过 k-v 对形式,存放在一个属性中)
- 如,商品属性(业务中的商品属性,与维度模型中的维度属性含义不同),可以通过 k-v (key - value)对的形式放在 property 字段中——10281239 :156426871;137369765:29229;
- 特点:扩展性好,但数据使用麻烦;
- 方式 2:保留维度主键不变,将多值属性放在维度的多个属性字段中;(每个值作为一个属性,分成多个属性存储)
- 如,卖家主营类目,卖家可能同时卖男装、女装、内衣等多种类型,所有卖家主营类目可能有多个;
- 业务要求:卖家主营类目 TOP3;
- 维度的多值属性字段具体值是数量固定(3 个),可以采用多个属性字段进行存储,方便数据统计分析和报表展示;
- 多值属性字段具体值的数量不固定,可以采用预留字段的方式;
- 如,卖家主营类目,卖家可能同时卖男装、女装、内衣等多种类型,所有卖家主营类目可能有多个;
- 方式 3:维度主键发生变化,一个维度值存放多条记录;
- 如,商品 SKU 维表,对于每个商品,有多少 SKU 就有多少条记录,主键是商品的 ID 和 SKU 的 ID;
- 优劣:扩展性好,使用方便,但是需要考虑数据的急剧膨胀情况;
5、杂项维度
- 杂项维度(Junk Dimension):有操作型系统中的指示符或者标志字段组合而成的,一般不在一致性维度之列;
- 理解:杂项,顾名思义,一些其它的非主要属性;
- 如,淘宝交易订单的交易类型字段,包括话费充值、司法拍卖、航旅、支付状态、物流状态等,它们在源系统中直接保存在交易表中;
- 背景:一个事实表中可能会存在多个非主要属性数据的字段;
- 如果将它们作为事实存放在事实表中,会导致事实表占用空间过大;
- 如果单独建立维表,外键关联事实表,则会出现维度过多;
- 如果将它们删除,但有些人会需要;
- 建立杂项维表:
- 使用多个杂项属性的字段的不同取值,组成一条记录,生成代理键,存入维表中,并将该代理键保存到相应的事实表字段下;
- 建议:不要直接使用所有的组合生成完整的杂项维表,而是在抽取到新的组合时,生成响应的记录即可;
- 在分布式计算系统中,由于生成代理键较为复杂,一般在逻辑模型中,使用实体的主键作为杂项维度的主键;
- 子订单维度一般是逻辑模型,物理实现时不进行物理化;
- 订单杂项维度和其他维度一起,会将维度属性退化至事实表中;