hive中拉鍊表

在有些情況下,爲了保持歷史的一些狀態,需要用拉鍊表來做,這樣做目的在可以保留所有狀態的情況下可以節省空間。

拉鍊表適用於以下幾種情況吧

數據量有點大,表中某些字段有變化,但是呢變化的頻率也不是很高,業務需求呢又需要統計這種變化狀態,每天全量一份呢,有點不太現實,

不僅浪費了存儲空間,有時可能業務統計也有點麻煩,這時,拉鍊表的作用就提現出來了,既節省空間,又滿足了需求。

一般在數倉中通過增加begin_date,en_date來表示,如下例,後兩列是start_date和end_date.

1
2
3
4
5
6
7
8
9
10
1  2016-08-20  2016-08-20  創建 2016-08-20  2016-08-20
1  2016-08-20  2016-08-21  支付 2016-08-21  2016-08-21
1  2016-08-20  2016-08-22  完成 2016-08-22  9999-12-31
2  2016-08-20  2016-08-20  創建 2016-08-20  2016-08-20
2  2016-08-20  2016-08-21  完成 2016-08-21  9999-12-31
3  2016-08-20  2016-08-20  創建 2016-08-20  2016-08-21
3  2016-08-20  2016-08-22  支付 2016-08-22  9999-12-31
4  2016-08-21  2016-08-21  創建 2016-08-21  2016-08-21
4  2016-08-21  2016-08-22  支付 2016-08-22  9999-12-31
5  2016-08-22  2016-08-22  創建 2016-08-22  9999-12-31

begin_date表示該條記錄的生命週期開始時間,end_date表示該條記錄的生命週期結束時間;

end_date = ‘9999-12-31’表示該條記錄目前處於有效狀態;

如果查詢當前所有有效的記錄,則select * from order_his where dw_end_date = ‘9999-12-31′

如果查詢2016-08-21的歷史快照,則select * from order_his where begin_date <= ‘2016-08-21′ and end_date >= ‘2016-08-21’

再簡單介紹一下拉鍊表的更新:

假設以天爲維度,以每天的最後一個狀態爲當天的最終狀態。

以一張訂單表爲例,如下是原始數據,每天的訂單狀態明細

1
2
3
4
5
6
7
8
9
10
1   2016-08-20  2016-08-20  創建
2   2016-08-20  2016-08-20  創建
3   2016-08-20  2016-08-20  創建
1   2016-08-20  2016-08-21  支付
2   2016-08-20  2016-08-21  完成
4   2016-08-21  2016-08-21  創建
1   2016-08-20  2016-08-22  完成
3   2016-08-20  2016-08-22  支付
4   2016-08-21  2016-08-22  支付
5   2016-08-22  2016-08-22  創建

根據拉鍊表我們希望得到的是

1
2
3
4
5
6
7
8
9
10
1  2016-08-20  2016-08-20  創建 2016-08-20  2016-08-20
1  2016-08-20  2016-08-21  支付 2016-08-21  2016-08-21
1  2016-08-20  2016-08-22  完成 2016-08-22  9999-12-31
2  2016-08-20  2016-08-20  創建 2016-08-20  2016-08-20
2  2016-08-20  2016-08-21  完成 2016-08-21  9999-12-31
3  2016-08-20  2016-08-20  創建 2016-08-20  2016-08-21
3  2016-08-20  2016-08-22  支付 2016-08-22  9999-12-31
4  2016-08-21  2016-08-21  創建 2016-08-21  2016-08-21
4  2016-08-21  2016-08-22  支付 2016-08-22  9999-12-31
5  2016-08-22  2016-08-22  創建 2016-08-22  9999-12-31

可以看出 1,2,3,4每個訂單的狀態都有,並且也能統計到當前的有效狀態。

本例以hive爲例,只考慮到實現,與性能無關

首先創建表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
CREATE TABLE orders (
orderid INT,
createtime STRING,
modifiedtime STRING,
status STRING
) row format delimited fields terminated by '\t'
 
 
CREATE TABLE ods_orders_inc (
orderid INT,
createtime STRING,
modifiedtime STRING,
status STRING
) PARTITIONED BY (day STRING)
row format delimited fields terminated by '\t'
 
 
CREATE TABLE dw_orders_his (
orderid INT,
createtime STRING,
modifiedtime STRING,
status STRING,
dw_start_date STRING,
dw_end_date STRING
) row format delimited fields terminated by '\t' ;

首先全量更新,我們先到2016-08-20爲止的數據。

初始化,先把2016-08-20的數據初始化進去

1
2
3
4
INSERT overwrite TABLE ods_orders_inc PARTITION (day '2016-08-20')
SELECT orderid,createtime,modifiedtime,status
FROM orders
WHERE createtime < '2016-08-21' and modifiedtime <'2016-08-21';

刷到dw中

1
2
3
4
5
6
INSERT overwrite TABLE dw_orders_his
SELECT orderid,createtime,modifiedtime,status,
createtime AS dw_start_date,
'9999-12-31' AS dw_end_date
FROM ods_orders_inc
WHERE day '2016-08-20';

如下結果

1
2
3
4
5
select from dw_orders_his;
OK
1  2016-08-20  2016-08-20  創建 2016-08-20  9999-12-31
2  2016-08-20  2016-08-20  創建 2016-08-20  9999-12-31
3  2016-08-20  2016-08-20  創建 2016-08-20  9999-12-31

剩餘需要進行增量更新

1
2
3
4
5
6
7
8
9
10
INSERT overwrite TABLE ods_orders_inc PARTITION (day '2016-08-21')
SELECT orderid,createtime,modifiedtime,status
FROM orders
WHERE (createtime = '2016-08-21'  and modifiedtime = '2016-08-21'OR modifiedtime = '2016-08-21';
 
select from ods_orders_inc where day='2016-08-21';
OK
1  2016-08-20  2016-08-21  支付 2016-08-21
2  2016-08-20  2016-08-21  完成 2016-08-21
4  2016-08-21  2016-08-21  創建 2016-08-21

先放到增量表中,然後進行關聯到一張臨時表中,在插入到新表中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
DROP TABLE IF EXISTS dw_orders_his_tmp;
CREATE TABLE dw_orders_his_tmp AS
SELECT orderid,
createtime,
modifiedtime,
status,
dw_start_date,
dw_end_date
FROM (
    SELECT a.orderid,
    a.createtime,
    a.modifiedtime,
    a.status,
    a.dw_start_date,
    CASE WHEN b.orderid IS NOT NULL AND a.dw_end_date > '2016-08-21' THEN '2016-08-21' ELSE a.dw_end_date END AS dw_end_date
    FROM dw_orders_his a
    left outer join (SELECT FROM ods_orders_inc WHERE day '2016-08-21') b
    ON (a.orderid = b.orderid)
    UNION ALL
    SELECT orderid,
    createtime,
    modifiedtime,
    status,
    modifiedtime AS dw_start_date,
    '9999-12-31' AS dw_end_date
    FROM ods_orders_inc
    WHERE day '2016-08-21'
) x
ORDER BY orderid,dw_start_date;
 
INSERT overwrite TABLE dw_orders_his
SELECT FROM dw_orders_his_tmp;

在根據上面步驟把2016-08-22號的數據更新進去,最後結果如下

1
2
3
4
5
6
7
8
9
10
11
12
select from dw_orders_his;
OK
1  2016-08-20  2016-08-20  創建 2016-08-20  2016-08-20
1  2016-08-20  2016-08-21  支付 2016-08-21  2016-08-21
1  2016-08-20  2016-08-22  完成 2016-08-22  9999-12-31
2  2016-08-20  2016-08-20  創建 2016-08-20  2016-08-20
2  2016-08-20  2016-08-21  完成 2016-08-21  9999-12-31
3  2016-08-20  2016-08-20  創建 2016-08-20  2016-08-21
3  2016-08-20  2016-08-22  支付 2016-08-22  9999-12-31
4  2016-08-21  2016-08-21  創建 2016-08-21  2016-08-21
4  2016-08-21  2016-08-22  支付 2016-08-22  9999-12-31
5  2016-08-22  2016-08-22  創建 2016-08-22  9999-12-31

至此,就得到了我們想要的數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章