Hudi實現(xiàn)拉鏈表實戰(zhàn)
1 基于Hudi表實現(xiàn)拉鏈表的方案
- 由于Hudi表存儲為了保證數(shù)據(jù)唯一性要求有主鍵,拉鏈表會對某一個對象的歷史狀態(tài)都存儲所以主鍵設計為聯(lián)合主鍵,將對象ID和生效時間作為聯(lián)合主鍵。
- Hudi新增了數(shù)據(jù)的更新能力,因此相對于傳統(tǒng)的大數(shù)據(jù)平臺,可以基于update的能力優(yōu)化傳統(tǒng)hive的拉鏈表的實現(xiàn)方案。
- 增量數(shù)據(jù)一般不攜帶歷史數(shù)據(jù)的生效時間
2 拉鏈表實現(xiàn)算法
- 當前最新的拉鏈表為Now_table(UserID:用戶ID,BundleID為套餐ID;Start_date為生效時間;End_date為失效效時間)
- 新增數(shù)據(jù)Tmp_table,(由于大數(shù)據(jù)平臺的數(shù)據(jù)基于上游采集而來,基于時間戳的增量數(shù)據(jù)相對容易獲取到)
- 新增數(shù)據(jù)Tmp_table與Now_table關聯(lián),將以存在數(shù)據(jù)更新寫入Now_table,end_date為當前時間
- 將新增數(shù)據(jù)全部寫入Now_table,end_date為'9999-12-31'
3 實現(xiàn)舉例
- 創(chuàng)建Now_table,并初始化數(shù)據(jù)
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());
- 新增數(shù)據(jù)臨時表Tmp_table,新增數(shù)據(jù)到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數(shù)據(jù)內容如下:
- 將Now_table數(shù)據(jù)閉鏈
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數(shù)據(jù)變更如下:
- 將增量數(shù)據(jù)開鏈寫入Now_table
insert into Now_table
select
userid,
bundleid,
start_date,
'9999-12-31',
now()
from Tmp_table
Now_table數(shù)據(jù)更新如下:
- 通過userid可以查詢到歷史的狀態(tài)變化。
select userid,bundleid,start_date,end_date from Now_table where userid='U0001';
4 算法總結
- Hudi表具有數(shù)據(jù)更新能力,不需要對全表數(shù)據(jù)進行insert overwrite操作,算法更簡單
- Hudi表提供Upsert的能力,當相同主鍵的數(shù)據(jù)存在,新數(shù)據(jù)會自動更新老數(shù)據(jù),因此不用對老數(shù)據(jù)進行update操作,直接Insert即可(Sparksql的Insert操作默認為upsert操作。)
- 對于緩慢變化維的操作會更加簡化,設置合理的主鍵,基于Merge語法直接操作,會更加簡單。
歡迎關注微信公眾號:大數(shù)據(jù)AI
評論
圖片
表情
