• [hive]维度模型分类:星型模型,雪花模型,星座模型|范式|数仓分层|用户纬度拉链表|维度建模


    数仓(十八)数仓建模以及分层总结(ODS、DIM、DWD、DWS、DWT、ADS层) - 墨天轮

    一、数仓分层

    1、ODS层:原始数据层

    ODS(O=original D=data S=store)

    1)设计要点

    存储来自多个业务系统、前端埋点、爬虫获取的一系列数据源的数据。

    我们要做三件事:

    【1】保持数据原貌不做任何修改,保留历史数据,起到数据备份的作用。

    【2】使用lzo压缩。100G的数据压缩之后大概为20G。

    【3】创建分区表,防止后续的全表扫描,一般按天存储。

    2)ODS层数据组成

    【1】前端埋点日志:由kafka或者flume采集到HDFS上

    flume采集的语句[flume]参数设置_胖胖学编程的博客-CSDN博客

    【2】由前端业务数据库用sqoop采集到HDFS上

    3)前端埋点日志的处理

    前端埋点日志以JSON格式形式存在

    建表语句

    1. create external table ods_log
    2. (
    3. line string
    4. )
    5. partitioned by (dt string)
    6. Stored as
    7. inputformat 'com.hadoop.mapred.DeprecatedLzoTextInputFormat'
    8. outputformat 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
    9. ;

    将flume落盘的数据建立lzo索引,否则无法分片

    1. hadoop jar /opt/module/hadoop-3.1.4/share/hadoop/common/hadoop-lzo-0.4.20.jar \
    2. com.hadoop.compression.lzo.DistributedLzoIndexer \
    3. -Dmapreduce.job.queuename=hive \
    4. /user/hive/warehouse/ods.db/ods_log/dt=2022-11-11

    加载建立好索引的数据

    1. load data inpath '/user/hive/warehouse/ods.db/ods_log/dt=2022-11-11'
    2. into table ods_log partition (dt='2022-11-11');

    4)MySQL数据库的处理

    mysql数据库的表通过sqoop采集到HDFS,使用\t作为分隔符,那ods层的表也要使用\t作为分割符;

    5)同步策略

    【1】增量同步:流量表(ods_flow_ph)

    也是埋点表,小时级增量表,所有的埋点数据都汇总在这一张表中。

    如果是用的apache hadoop就直接用flume拉取数据。

    要是用阿里的dataworks:包括调度+数据集成(从MySQL啥的导数据)+MaxCompute(类似hive,可以写sql)  注:一般用阿里的服务的话还用quickBI做报表展示。就是后端和前端将数据写入到kafka中,然后从kafka中每小时进行数据同步。

    【2】全量同步:用户表、订单表、看课表、课程表、章节表、教师表、互动表、卡片表

    【3】特殊:一次性拉取,不建分区表(DIM层的父数据)

    2、DIM

    dim=dimension

    存储为Parquet格式

    1)同步策略

    全量同步:商品维度,优惠券维度。首日和每日都是全量先导入到ODS再导入到DIM层

    特殊:日期,地区(自己处理)

    拉链表:用户维度表(见下面)

    3、DWD层

    dwd=data warehouse detail

    1)说明

    dwd层是对事实表的处理,代表的是业务的最小粒度层,任何数据的记录都可以从这一层获取,为后续的dws和dwt层做准备。

    dwd层是站在选择好事实表的基础上,对维度建模的视角。

    2)对埋点数据进行处理

    将ods.ods_log表唯一的字段line这个json串进行解析,并将其中的内容拆分为两个表:

    启动日志、事件日志

    3)对业务数据进行处理

    【1】周期快照事实表

    每天导入全量数据。

    如:购物车这个表,咱们只在乎购物车里有多少东西,不关注加减购物车内商品的操作

    【2】累计快照事实表(没看完)

    103-尚硅谷-数仓搭建-DWD层优惠券领用事实表_哔哩哔哩_bilibili

    如:优惠券领用,这种发生周期变化的场景

    领取->用券下单->用券支付->过期

    1. create table dwd_coupun_use(
    2. coupun_id string, --优惠券id
    3. user_id string, --用户id
    4. coupun_status string, --优惠券状态
    5. using_time string, --使用时间(下单)
    6. used_time string, --使用时间(支付)
    7. expire_time string --过期时间
    8. )
    9. partitioned by(dt string)
    10. ;

    4、dim和dwd

    DIM和DWD采用维度建模,一般采用星型模型,呈现状态一般为星座模型。详情见维度建模的步骤。

    5、dws、dwt、ads

    dws= data warehouse service

    dwt=data warehosue topic

    ads=application data store

    dws、dwt、ads都是以需求为驱动的,和纬度建模已经没有关系了。

    dws、dwt:统称为宽表层,这两层的设计思想大致相同,通过以下案例进行说明:

    1)问题引出

    两个需求,统计每个省份订单的个数、统计内个省份订单的总金额

    2)处理办法

    都是将省份和订单表进行join,group by省份,然后计算,同样的数据被计算了两次,实际上类似的场景还有很多,那怎么设计才能避免重复计算呢?针对上述场景可以设计一张地区表,其主键为地区ID,字段为:下单次数,下单金额,支付次数,支付金额等,上述所有指标统一进行计算,并将结果保存在该宽表中,这样就能有效避免数据的重复计算。

    3)需要那些宽表(主题表):以维度为基准

    4)DWS和DWT层的区别:

    DWS层存放所有当天的汇总行为,例如每个地区当天下单次数,下单金额等,dwt层存放的是所有主题对象的累计行为,例如每个地区最近7天(15天、30天、60天)的下单次数,下单金额等。

    5)ads层:存储各个报表需要的结果。

    二、DIM层用户维度拉链表

    1、什么是拉链表

    用于存储变化,但变化的频率较慢的数据。这样的数据用全量存存储大量重复数据,因此用拉链表。

    2、每条数据的意义

    该条数据的有效时间

    3、制造拉链表

    1)建表语句

    1. create table dim_user_info(
    2. id string,
    3. user_name string --用户名称,
    4. name string --真实姓名,
    5. phone_num string,
    6. gerder string --性别,
    7. email string,
    8. create_time string --创建时间,
    9. operate_time string --操作时间,
    10. start_date string --开始日期(拉链表特有),
    11. end_date string --结束日期(拉链表特有)
    12. )
    13. partitioned by(dt string)
    14. stored as parquet
    15. table properties("parquet.compression"="lzo")
    16. ;

    2) 分区规划:

    3)首日装载

    要进行初始化,ods层该表第一天从MySQL拉取的所有数据放到9999-99-99分区

    1. insert overwrite table dim.dim_user_info partition(dt='9999-99-99')
    2. select
    3. id,
    4. user_name,
    5. name,
    6. phone_num,
    7. gerder,
    8. email,
    9. create_time,
    10. operate_time,
    11. '2022-19-01' start_date,
    12. '9999-99-99' end_date
    13. from
    14. ods.ods_user_info
    15. where dt='2022-10-01'

    4)每日装载

     

    【1】将最新的数据装载到9999-99-99分区

    如果new为null(没有变化),则取old,

    如果new不为null(今日发生了新增及变化),则取new

    1. select
    2. if(new.id is not null,new.id,old.id) id,
    3. if(new.user_name is not null,new.user_name,old.user_name) user_name,
    4. if(new.name is not null,new.name,old.name) name,
    5. if(new.phone_num is not null,new.phone_num,old.phone_num) num,
    6. if(new.gerder is not null,new.gerder,old.gerder) gerder,
    7. if(new.email is not null,new.email,old.email) nemail,
    8. if(new.create_time is not null,new.create_time,old.create_time) create_time ,
    9. if(new.operate_time is not null,new.operate_time,old.operate_time) operate_time,
    10. if(new.start_date is not null,new.start_date,old.start_date) start_date,
    11. if(new.end_date is not null,new.end_date,old.end_date) end_date
    12. (
    13. select
    14. id,
    15. user_name,
    16. name,
    17. phone_num,
    18. gerder,
    19. email,
    20. create_time,
    21. operate_time,
    22. '2022-19-01' start_date,
    23. '9999-99-99' end_date
    24. from
    25. dim.dim_user_info
    26. where dt='9999-99-99'
    27. )ods
    28. full join
    29. (
    30. select
    31. id,
    32. user_name,
    33. name,
    34. phone_num,
    35. gerder,
    36. email,
    37. create_time,
    38. operate_time,
    39. '2022-10-01' start_date,
    40. '9999-99-99' end_date --新增及变化的数据都是最新数据
    41. from
    42. ods.ods_user_info --ods_user_info表是每日增量导入的
    43. where dt='2022-10-01' --新增及变化的数据
    44. )new
    45. on ods.id=new.id

      【2】将过期数据装载到前一天的分区(注意日期之间没有重合)

    new和old都有的数据取old的

    1. select
    2. old.id id,
    3. old.user_name user_name,
    4. old.name name,
    5. old.phone_num num,
    6. old.gerder gerder,
    7. old.email nemail,
    8. old.create_time create_time ,
    9. old.operate_time operate_time,
    10. old.start_date start_date,
    11. old.end_date end_date
    12. (
    13. select
    14. id,
    15. user_name,
    16. name,
    17. phone_num,
    18. gerder,
    19. email,
    20. create_time,
    21. operate_time,
    22. '2022-19-01' start_date,
    23. '9999-99-99' end_date
    24. from
    25. dim.dim_user_info
    26. where dt='9999-99-99'
    27. )ods
    28. full join
    29. (
    30. select
    31. id,
    32. user_name,
    33. name,
    34. phone_num,
    35. gerder,
    36. email,
    37. create_time,
    38. operate_time,
    39. '2022-10-01' start_date,
    40. '9999-99-99' end_date --新增及变化的数据都是最新数据
    41. from
    42. ods.ods_user_info --ods_user_info表是每日增量导入的
    43. where dt='2022-10-01' --新增及变化的数据
    44. )new
    45. on ods.id=new.id
    46. where new.id is not null and old.id is not null
    47. ;

     4.对拉链表进行查询

    1)获取在某天有效的的所有用户的数据

    1. --获取2019-01-01有效的所有历史数据
    2. select * from user_info where start_date<='2019-01-01' and end_date>='2019-01-01';

    2)获取目前所有用户的最新的数据

    select * from user_info where end_date>='9999-99-99';

     三、纬度建模

    纬度建模步骤:选择业务过程声明粒度、确认纬度、确认事实

    1、选择业务过程

    整个业务流程中选取我们需要建模的业务,根据公司业务提供的需求及日后的易扩展性等进行选择业务。

    这里我们选择了几个业务过程是:支付、订单、加购物车、优惠券领用、收藏、评论、退款等。

    2、声明粒度

    总体采用最小粒度规则,不做任何聚合操作。

    声明力度意味着定义事实表中的一行数据表示什么,应尽可能选择最小粒度,以此来应对各种各样的需求。

    3、确认纬度

    确定维度对象,维度的主要作用是描述业务事实,主要表示的是:“谁、何处、何时”等信息。

    确定维度的原则是:后续需求中是否要分析相关维度的指标。例如:需要统计哪个用户下的订单多,哪个地区下的订单多,什么地区下单多,需要确定的维度就包括:用户维度,地区维度,时间维度。

    4、确认事实

    事实表只有纬度id和度量值。

  • 相关阅读:
    ffmeg 中fftools/Makefile 分析
    VMware vCenter Server 6.7 安装
    Python FastApi 解决跨域及OPTIONS预请求处理
    Java设计模式 _创建型模式_工厂模式(普通工厂和抽象工厂)
    在windows10 安装子系统linux(WSL安装方式)
    Java落寞了?7 月编程语言最新排行榜
    html知识点总结
    SpringBoot(一、快速入门)
    nio-buffer
    代码重构:解读重构概念及重构实战
  • 原文地址:https://blog.csdn.net/qq_35896718/article/details/127744076