大数据,机器学习,人工智能大数据 爬虫Python AI Sql大数据

hive中拉链表

2019-12-06  本文已影响0人  叫我老村长

在有些情况下,为了保持历史的一些状态,需要用拉链表来做,这样做目的在可以保留所有状态的情况下可以节省空间。

拉链表适用于以下几种情况吧

数据量有点大,表中某些字段有变化,但是呢变化的频率也不是很高,业务需求呢又需要统计这种变化状态,每天全量一份呢,有点不太现实,

不仅浪费了存储空间,有时可能业务统计也有点麻烦,这时,拉链表的作用就提现出来了,既节省空间,又满足了需求。

一般在数仓中通过增加begin_date,en_date来表示,如下例,后两列是start_date和end_date.

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 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 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为例,只考虑到实现,与性能无关

首先创建表

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的数据初始化进去

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中

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'``;

如下结果

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

剩余需要进行增量更新

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

先放到增量表中,然后进行关联到一张临时表中,在插入到新表中

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号的数据更新进去,最后结果如下

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

至此,就得到了我们想要的数据。

上一篇 下一篇

猜你喜欢

热点阅读