如何基于MRS-Hudi实现拉链表

举报
受春柏 发表于 2022/05/24 11:12:19 2022/05/24
【摘要】 拉链表是缓慢变化维的一种实现形式,是数据仓库的常用数据模型。基于传统大数据需要全量覆盖写的模式进行,基于Hudi的能力,实现方案会更加简单,性能更优。

拉链表介绍

数据仓库中有一种数据存储模型,用于维护历史状态以及最新状态,反映某一Key的历史变化演进过程,该种模型叫做缓慢变化维,简称SCDSlowly Changing Dimensions),通常所说的拉链表其实属于缓慢变化维的一种实现方式,拉链表通过增加一列维度信息维护拉链状态,他们之间稍微有所不同,具体区别如下:

相同点:

缓慢变化维度,简称SCD (Slowly Changing Dimensions)和拉链表都是为了存储非静态数据的历史变化状态。

不同点:

拉链表有开链和闭链过程,总一条数据明确表示最新状态(例如常见的End_date=9999-12-31 00:00:00,针对的大都是事实表。

缓慢变化维,没有开链与闭链过程,只是单纯的记录数据的变化过程,解决的也都是维度表的存储,反映维度的数据历史演进过程。

具体举例如下:

  • 缓慢变化维

缓慢变化维的变化相对拉链表要简单很多,直接插入最新状态即可,例如A02套餐内容中通话时长更新为2000分钟后,变化后的结果如下:

  • 拉链表

在实现上增加了时效时间字段,用于表示保存变化后的最新状态值

  具体实现如下:例如用户U0001更新了新套餐A02,操作如下

  • 将当前最新状态数据更新,也就是闭链操作

变更为:

 

  • 将最新状态数据插入,也就是开链操作

  • 最终结果为:

基于Hudi表实现拉链表的方案

  • 由于Hudi表存储为了保证数据唯一性要求有主键,拉链表会对某一个对象的历史状态都存储所以主键设计为联合主键,将对象ID和生效时间作为联合主键。
  • Hudi新增了数据的更新能力,因此相对于传统的大数据平台,可以基于update的能力优化传统hive的拉链表的实现方案。
  • 增量数据一般不携带历史数据的生效时间

拉链表实现算法

  1. 当前最新的拉链表为Now_table(UserID:用户ID,BundleID为套餐ID;Start_date为生效时间;End_date为失效效时间)
  2. 新增数据Tmp_table,(由于大数据平台的数据基于上游采集而来,基于时间戳的增量数据相对容易获取到)
  3. 新增数据Tmp_data与Now_table关联,将以存在数据更新写入Now_table,end_date为当前时间
  4. 将新增数据全部写入Now_table,end_date为‘9999-12-31’

实现举例

  • 创建Now_table,并初始化数据
Create table  Now_table(
    userid  string,
    bundleid string,
    start_date string,
    end_date  string,
    ts  timestamp
)using hudi
OPTIONS(
  type = 'mor',
`payloadClass` 'org.apache.hudi.common.model.DefaultHoodieRecordPayload',
  primaryKey = 'userid,start_date',
  preCombineField = 'ts'
 );
insert into Now_table(userid,bundleid,start_date,end_date) values('U0001','A01','2020-05-31','2021-05-31',now());
insert into Now_table(userid,bundleid,start_date,end_date) values('U0001','A01','2021-05-31','9999-12-31',now());
insert into Now_table(userid,bundleid,start_date,end_date) values('U0002','A01','2020-05-31','2021-05-31',now());
insert into Now_table(userid,bundleid,start_date,end_date) values('U0002','A02','2021-05-31','9999-12-31',now());

    • 新增数据临时表Tmp_table,新增数据到Tmp_table
    Create table  Tmp_table(
        userid  string,
        bundleid string,
        start_date string
    )using hudi
    OPTIONS(
      type = 'mor',
      primaryKey = 'userid',
      preCombineField = 'start_date'
     );
    insert into Tmp_table(userid,bundleid,start_date) values('U0001','A03','2022-05-31');
    insert into Tmp_table(userid,bundleid,start_date) values('U0002','A03','2022-05-31');
    insert into Tmp_table(userid,bundleid,start_date) values('U0003','A03','2022-05-31');

    Tmp_table数据内容如下:

    • 将Now_table数据闭链
    insert into Now_table select t1.userid,t1.bundleid,t1.start_date,t2.start_date,now() from Now_table t1,Tmp_table t2 where t1.userid= t2.userid and t1.end_date='9999-12-31';

    Now_table数据变更如下:

    • 将增量数据开链写入Now_table
    insert into Now_table select userid,bundleid,start_date,'9999-12-31',now() from Tmp_table

    Now_table数据更新如下:

     

    • 通过userid可以查询到历史的状态变化。
    select userid,bundleid,start_date,end_date from Now_table where userid='U0001';

     算法总结

    •  Hudi表具有数据更新能力,不需要对全表数据进行insert overwrite操作,算法更简单
    •  Hudi表提供Upsert的能力,当相同主键的数据存在,新数据会自动更新老数据,因此不用对老数据进行update操作,直接Insert即可(Sparksql的Insert操作默认为upsert操作。)
    • 对于缓慢变化维的操作会更加简化,设置合理的主键,基于Merge语法直接操作,会更加简单。
    【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
    • 点赞
    • 收藏
    • 关注作者

    评论(0

    0/1000
    抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。