电商5.0

1. 数仓概述

参考:尚硅谷

数据仓库是一个为数据分析而设计的企业级数据管理系统

数据仓库可集中、整合多个信息源的大量数据,借助数据仓库的分析能力,企业可从数据中获得宝贵的信息进而改进决策

同时,随着时间的推移,数据仓库中积累的大量历史数据对于数据科学家和业务分析师也是十分宝贵的


2. 维度建模理论

2.1 事实表

概述

事实表作为数据仓库维度建模的核心,紧紧围绕着 业务过程 来设计

其包含与该业务过程有关的维度引用(维度表外键)以及该业务过程的度量(通常是可累加的数字类型字段)

特点

事实表通常比较 “细长”,即列较少,但行较多,且行的增速快


分类

  1. 事务型事实表 (重点)

    事务型事实表用来记录各业务过程,它保存的是各业务过程的原子操作事件,即最细粒度的操作事件

    粒度是指事实表中一行数据所表达的业务细节程度

    事务型事实表可用于分析与各业务过程相关的各项统计指标,由于其保存了最细粒度的记录,可以提供最大限度的灵活性,可以支持无法预期的各种细节层次的统计需求

    设计流程: 选择业务过程 → 声明粒度 → 确认维度 → 确认事实

    不足:存量型指标多事务关联统计

  2. 周期型快照事实表

    周期快照事实表以具有规律性的、可预见的时间间隔来记录事实,主要用于分析一些存量型(例如商品库存,账户余额)或者状态型(空气温度,行驶速度)指标

    对于商品库存、账户余额这些存量型指标,业务系统中通常就会计算并保存最新结果,所以定期同步一份全量数据到数据仓库,构建周期型快照事实表,就能轻松应对此类统计需求,而无需再对事务型事实表中大量的历史记录进行聚合了

    对于空气温度、行驶速度这些状态型指标,由于它们的值往往是连续的,我们无法捕获其变动的原子事务操作,所以无法使用事务型事实表统计此类需求。而只能定期对其进行采样,构建周期型快照事实表

  3. 累积型快照事实表

    累计快照事实表是基于一个业务流程中的多个关键业务过程联合处理而构建的事实表,如交易流程中的下单、支付、发货、确认收货业务过程

    累积型快照事实表通常具有多个日期字段,每个日期对应业务流程中的一个关键业务过程(里程碑)

    累积型快照事实表主要用于分析业务过程(里程碑)之间的时间间隔等需求。例如前文提到的用户下单到支付的平均时间间隔,使用累积型快照事实表进行统计,就能避免两个事务事实表的关联操作,从而变得十分简单高效


2.2 维度表

概述

维度表是维度建模的基础和灵魂

事实表紧紧围绕业务过程进行设计,而维度表则围绕 业务过程所处的环境 进行设计

维度表主要包含一个主键和各种维度字段,维度字段称为维度属性

设计步骤

  • 确定维度(表)

    在设计事实表时,已经确定了与每个事实表相关的维度,理论上每个相关维度均需对应一张维度表。需要注意到,可能存在多个事实表与同一个维度都相关的情况,这种情况需保证维度的唯一性,即只创建一张维度表

    另外,如果某些维度表的维度属性很少,例如只有一个**名称,则可不创建该维度表,而把该表的维度属性直接增加到与之相关的事实表中,这个操作称为维度退化

  • 确定主维表和相关维表

    此处的主维表和相关维表均指业务系统中与某维度相关的表。例如业务系统中与商品相关的表有sku_info,spu_info,base_trademark,base_category3,base_category2,base_category1等,其中sku_info就称为商品维度的主维表,其余表称为商品维度的相关维表。粒度比较小的通常是主维表,维度表的粒度通常与主维表相同

  • 确定维度属性

    确定维度属性即确定维度表字段。维度属性主要来自于业务系统中与该维度对应的主维表和相关维表

    维度属性可直接从主维表或相关维表中选择,也可通过进一步加工得到

    确定维度属性时,需要遵循以下要求:

    • 尽可能生成丰富的维度属性

      维度属性是后续做分析统计时的查询约束条件、分组字段的基本来源,是数据易用性的关键。维度属性的丰富程度直接影响到数据模型能够支持的指标的丰富程度

    • 尽量不使用编码,而使用明确的文字说明,一般可以编码和文字共存

    • 尽量沉淀出通用的维度属性

      有些维度属性的获取需要进行比较复杂的逻辑处理,例如需要通过多个字段拼接得到。为避免后续每次使用时的重复处理,可将这些维度属性沉淀到维度表中


设计要点

规范化与反规范化

规范化是指使用一系列范式设计数据库的过程,其目的是减少数据冗余,增强数据的一致性。通常情况下,规范化之后,一张表的字段会拆分到多张表。

反规范化是指将多张表的数据冗余到一张表,其目的是减少join操作,提高查询性能。

数据仓库系统的主要目的是用于数据分析和统计,所以是否方便用户进行统计分析决定了模型的优劣。采用雪花模型,用户在统计分析的过程中需要大量的关联操作,使用复杂度高,同时查询性能很差,而采用星型模型,则方便、易用且性能好

所以出于易用性和性能的考虑,维度表一般是很不规范化的

维度变化

维度属性通常不是静态的,而是会随时间变化的,数据仓库的一个重要特点就是反映历史的变化,所以如何保存维度的历史状态是维度设计的重要工作之一。保存维度数据的历史状态,通常有以下两种做法,分别是全量快照表和拉链表

1)全量快照表

​ 离线数据仓库的计算周期通常为每天一次,所以可以每天保存一份全量的维度数据。这种方式的优点和缺点都很明显

优点是简单而有效,开发和维护成本低,且方便理解和使用

缺点是浪费存储空间,尤其是当数据的变化比例比较低时

2)拉链表

​ 拉链表的意义就在于能够更加高效的保存维度信息的历史状态


多值维度

如果事实表中一条记录在某个维度表中有多条记录与之对应,称为多值维度

例如,下单事实表中的一条记录为一个订单,一个订单可能包含多个商品,所会商品维度表中就可能有多条数据与之对应

针对这种情况,通常采用以下两种方案解决:

​ 第一种:降低事实表的粒度,例如将订单事实表的粒度由一个订单降低为一个订单中的一个商品项

​ 第二种:在事实表中采用多字段保存多个维度值,每个字段保存一个维度id。这种方案只适用于多值维度个数固定的情况

建议尽量采用 第一种方案 解决多值维度问题

多值属性

维表中的某个属性同时有多个值,称之为 多值属性

例如商品维度的平台属性和销售属性,每个商品均有多个属性值

针对这种情况,通常有可以采用以下两种方案:

​ 第一种:将多值属性放到一个字段,该字段内容为key1:value1,key2:value2的形式,例如一个手机商品的平台属性值为 “品牌:华为,系统:鸿蒙,CPU:麒麟990”

​ 第二种:将多值属性放到多个字段,每个字段对应一个属性。这种方案只适用于多值属性个数固定的情况


3. 数仓分层规划

维度表中的信息既可以被明细表关联,也可以被汇总表关联(维度退化)


4. 构建流程


4.1 数据调研

  • 业务调研

    熟悉业务流程、熟悉业务数据

  • 需求分析

    需要明确需求所需的业务过程维度,例如该需求所需的业务过程就是买家下单,所需的维度有日期,省份,商品品类

  • 总结

    做完业务分析和需求分析之后,要保证每个需求都能找到与之对应的业务过程及维度

    若现有数据无法满足需求,则需要和业务方进行沟通,例如某个页面需要新增某个行为的埋点


4.2 明确数据域

数据仓库模型设计除横向的分层外,通常也需要根据业务情况进行纵向划分数据域

划分数据域的意义是便于数据的管理和应用

通常可以根据业务过程或者部门进行划分,本项目根据业务过程进行划分,需要注意的是一个业务过程只能属于一个数据域


4.3 构建业务总线矩阵

业务总线矩阵中包含维度模型所需的所有事实(业务过程)以及维度,以及各业务过程与各维度的关系

矩阵的行是一个个业务过程,矩阵的列是一个个的维度,行列的交点表示业务过程与维度的关系


4.4 明确统计指标

明确统计指标具体的工作是,深入分析需求,构建指标体系

构建指标体系的主要意义就是指标定义标准化。所有指标的定义,都必须遵循同一套标准,这样能有效的避免指标定义存在歧义,指标定义重复等问题

  • 指标体系相关概念

    1)原子指标

    原子指标基于某一业务过程度量值,是业务定义中不可再拆解的指标,原子指标的核心功能就是对指标的聚合逻辑进行了定义。我们可以得出结论,原子指标包含三要素,分别是业务过程、度量值和聚合逻辑

    例如订单总额就是一个典型的原子指标,其中的业务过程为 用户下单、度量值为订单金额,聚合逻辑为sum() 求和

    需要注意的是原子指标只是用来辅助定义指标一个概念,通常不会对应有实际统计需求与之对应

    2)派生指标

    派生指标基于原子指标,其与原子指标的关系如下图所示

    与原子指标不同,派生指标通常会对应实际的统计需求。请从图中的例子中,体会指标定义标准化的含义


    3)衍生指标

    衍生指标是在一个或多个派生指标的基础上,通过各种逻辑运算复合而成的。例如比率、比例等类型的指标。衍生指标也会对应实际的统计需求

  • 指标体系对于数仓建模的意义

    通过上述两个具体的案例可以看出,绝大多数的统计需求,都可以使用原子指标、派生指标以及衍生指标这套标准去定义。同时能够发现这些统计需求都直接的或间接的对应一个或者是多个派生指标

    当统计需求足够多时,必然会出现部分统计需求对应的派生指标相同的情况。这种情况下,我们就可以考虑将这些公共的派生指标保存下来,这样做的主要目的就是减少重复计算,提高数据的复用性

    这些公共的派生指标统一保存在数据仓库的DWS层。因此DWS层设计,就可以参考我们根据现有的统计需求整理出的派生指标


4.5 维度模型设计

维度模型的设计参照上述得到的业务总线矩阵即可。事实表存储在DWD层,维度表存储在DIM层

4.6 汇总模型设计

汇总模型的设计参考上述整理出的指标体系(主要是派生指标)即可

汇总表与派生指标的对应关系是,一张汇总表通常包含业务过程相同、统计周期相同、统计粒度相同的多个派生指标

请思考:汇总表与事实表的对应关系是?


5. 数据仓库开发环境

数仓开发工具可选用DBeaver或者DataGrip

两者都需要用到JDBC协议连接到Hive,故需要首先启动 HiveServer2


6. 数仓开发

6.1 ODS层

职责:保存原始数据,不做任何处理

ODS层设计要点

  • ODS层 的表结构设计依托于 从 业务系统 同步过来的数据结构(核心

    1. Hive SerDe,每一张表都会有默认的 SerDe

      • SerDe is a short name for "Serializer and Deserializer." (序列化器和反序列化器)
      • Hive uses SerDe (and FileFormat) to read and write table rows.
      • HDFS files --> InputFileFormat --> <key, value> --> Deserializer --> Row object
      • Row object --> Serializer --> <key, value> --> OutputFileFormat --> HDFS files

    2. Hive 根据 json 建表的语法

      表的字段值需要与 json 的 key 值一致,字段的顺序不重要

      如果字段名不完全一致,是不会报错的,但是不会获取到相应的值(留null)

      --{"id":1001,"name":"zhangsan"}
      CREATE TABLE person(id int, name string)
      ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.JsonSerDe'
      location '/person';
      

      测试:load data local inpath '/home/atguigu/person' into table person;

      注意 执行 load 语句时需要在 保存相应本地文件的机子上执行


    3. 对于包含嵌套字段的 json,与 一级字段 保持一致即可,值用 复杂对象类型 (array、map、struct) 即可

      定义:array<string> , map<string, bigint> , struct<id:int, name:string>

      ​ 使用结构体时 字段得是确定的,如果不确定可以用 map,统一使用string再转回来

      取值:arr[idx] , map[key] , struct.key

      构造:array(val1, val2, ...) , split() , collect_set():聚合函数,多进一出 ;

      ​ map(key1, value1, key2, value2, ...) , str_to_map() ;

      ​ struct(val1, val2, val3, ...) , named_struct(name1, val1, name2, val2, ...)


  • ODS层要保存 全部历史数据,故其压缩格式应选择压缩比较高的,此处选择 gzip,对不同格式的文件操作不同

    You can import text files compressed with Gzip or Bzip2 directly into a table stored as TextFile

  • ODS层表名的 命名规范 为:ods_表名_单分区增量全量标识(inc/full),这里的表名就是业务系统中的表名,一天对应一个分区


元数据显示问题

Datagrip 显示问题,json 表没有显示相应字段,问题在于元数据

在hive配置文件hive-site.xml 中加上一个参数

<property>
    <name>metastore.storage.schema.reader.impl</name>
    <value>org.apache.hadoop.hive.metastore.SerDeStorageSchemaReader</value>
</property>

表的注释 乱码问题

修改元数据中相应表的注释字段的字符集为utf-8,然后修改hive-site.xml中的jdbc url编码为utf8, 在xml中需要用&的转义为 '&amp;'

但是如果是对于已经建的表 仍然是 不能正常显示的,只能删除重建,由于是外部表数据是不会丢失的,但是需要添加分区信息后才能看见数据,需要修复元数据

msck repair table XXX;

6.2 DIM层

DIM层设计要点

Hive的分区是为了方便以后进行查询,所以全量表可以按天进行分区;而拉链表可以将全量最新的放在一个分区(极大值),其他状态更改的(当日过期的)放在一个分区(哪天过期的就放在哪一天)

select + insert :数据从哪来(ODS层),到哪儿去(DIM层)

要想知道事实表的数据从哪儿来的,就得知道这张表对应的业务过程 会对哪张表产生影响!

全量表 数据装载的逻辑:拿到ODS层相应表的某一天的数据,幂等(overwrite)地装载到分区中

拉链表的意义就在于能够更加高效的保存维度信息的历史状态,适用于变化不多的情况

拉链表 装载逻辑:第一天先做一个全量同步,加上开始日期(给定一个初始值即可)和结束日期(极大值);第二天做增量同步(基于查询的拿不到中间状态,基于bin_log的可以拿到中间状态,但是只会用到最后一个状态),根据 用户变化表 合并拉链表,一个人的不同状态开始日期和结束日期是不应该有交集的,变化的部分到极大值分区,被更改的即过期的部分放到当日分区

  • DIM层的 设计依据 是维度建模理论,该层存储维度模型的维度表 (核心

  • DIM层的数据 存储格式 为 orc列式存储+snappy压缩

  • DIM层表名的 命名规范 为dim_表名_全量表或者拉链表标识(full/zip)


6.3 DWD层

DWD层设计要点

  • DWD层的设计依据是维度建模理论,该层存储维度模型的事实表

    首日进行动态分区,对所有数据进行统一处理;每日的数据(update/insert)才是真正意义上的增量数据,放在当日分区即可

  • DWD层的数据存储格式为 orc列式存储+snappy压缩

  • DWD层表名的命名规范为 dwd_数据域_表名_单分区增量全量标识(inc/full) 比如 事务事实表:inc,周期快照表:full


6.4 DWS层

为了减少重复计算,提高中间结果的复用性,DWS层的设计依托于 将来的需求

重点:派生指标 = 原子指标 + 统计周期 + 业务限定(相当于where) + 统计粒度(相当于group by)

实际上就是 分解需求,统计需求都 直接地或间接地 对应 一个或多个派生指标

当统计需求足够多时,必然会出现部分统计需求对应的派生指标相同的情况。这种情况下,我们就可以考虑将这些公共的派生指标保存下来,这样做的主要目的就是减少重复计算,提高数据的复用性


DWS层设计要点

  • DWS层的设计参考指标体系

    1)知道指标怎么算(比较麻烦),构建脑图

    ​ 怎么判断是衍生表还是派生表?看是否能根据一张事实表直接聚合得到,能则是派生表,否则就是衍生表

    ​ 维度和度量使用时并不是固定的,得看情况而定

    2)将指标放在excel表格中方便查看,后续将业务过程相同且统计周期相同且统计粒度相同的指标放在一张表中

    3)派生指标和DWS层的对应关系,如果一个派生指标对应DWS层的一张表(可能会导致DWS层的模型极其复杂),最终采用一个汇总表对应多个相近的派生指标(业务过程相同:采用的事实表相同 & 统计周期相同:拿的分区相同 & 统计粒度相同:结果的数据结构相同)的方式

  • DWS层的数据存储格式为 ORC列式存储 + snappy压缩

  • DWS层表名的命名规范为 dws_数据域_统计粒度_业务过程_统计周期(1d/nd/td) 数据域可以从DWD层直接继承而来,注:1d表示最近1日,nd表示最近n日,td表示历史至今;为什么分开?与数据装载有关,比如对于历史至今的数据每次需要加载全表;而且nd的数据可以从1d中获得,这样明细表就只需要汇总一次(汇总1d表时)

posted @ 2022-11-17 20:45  黄一洋  阅读(42)  评论(0)    收藏  举报