前提:
数仓中的维度,事实表技术提倡用代理键代替实体键,下面我们讲解下代理键的概念,以及Hive中如何生成代理键 (自增列)
代理键 :
维度表中必须有一个能够唯一标识一行记录的列,通过该列维护维度表与事实表之间的关系,一般在维度表中业务主键符合条件可以当作维度主键。
补充:
是由数据仓库处理过程中产生的,与业务本身无关的, 唯一标识维度表中一条记录并充当维度表主键的列,也是描述维度表与事实表关系的纽带。
所以在设计有代理键的维度表中,事实表中的关联键是代理键而不是原有的业务主键,即业务关系是靠代理键维护,这样有效避免源系统变化对数据仓库的影响。
在实际业务中,代理键通常是数值型,自增的值。
解决以下几类问题(部分问题):
1.当整合多个数据源的维度时,不同数据源的业务主键重复怎么办?
2.维度拉链表,同一主体对调记录,业务键重复如何去做
示例如下:
针对于多个数据源的数据。例如,下面两个不同来源的用户 :
技术部用户
Table S1
Id |
name |
note |
1 |
Da1 |
Tech-leader |
2 |
Jiang1 |
tech |
财务部用户
Table S2
Id |
name |
note |
1 |
Tian1 |
Finc-1 |
2 |
Tai |
Finc-2 |
整合成如下数据
Table dim_user
Uid |
id |
name |
note |
source |
1 |
1 |
Da1 |
Tech-leader |
S1 |
2 |
2 |
Jiang1 |
tech |
S1 |
3 |
1 |
Tian1 |
Finc-1 |
S2 |
4 |
2 |
Tai |
Finc-2 |
S2 |
实现的几种方式:
1)UDF 实现自增列。
2)Hive 中实现自增键
下面我们主要讲解下如何在Hive 中实现自增键: 即方式二:
假设我们从 Table S1 ,Table S2 都是增量采集的数据
第一步 :增量采集数据,构建每天增量表
S1, S2 -> Tmp_s_inc
采集SQL :
S1 :
SELECT * FROM S1 WHERE created_time > ‘2018-06-01’
S2:
SELECT * FROM S2 WHERE created_time > ‘2018-06-01’
最终SQL :
INSERT OVERWRITE TABLE Tmp_s_inc PARTITION( dt = ‘2018-06-01’)
SELECT
S1.*
,’S1’ AS source
FROM S1 WHERE created_time > ‘2018-06-01’
UNION ALL
SELECT
S2.*
,’S2’ AS source
FROM S2 WHERE created_time > ‘2018-06-01’
第二步:获取之前维度表,前一天的最大Uid (代理键), SQL 如下:
SELECT COALESCE(MAX(Uid, 0) FROM dim_user WHERE dt = ’2018-05-31 ’
第三步 :最终将生成的代理键的增量数据,结合前一天的数据插入到新的分区中:
INSERT OVERWRITE TABLE dim_user PARTITION (dt = ‘2018-06-01’)
SELECT
ROW_NUMBER() OVER(ORDER BY id) + ta.max_id AS uid
FROM tmp_s_inc AS tb
CROSS JOIN
(
SELECT COALESCE(MAX(Uid, 0) FROM dim_user WHERE dt = ’2018-05-31’
) AS ta
UNION ALL
SELECT
*
FROM dim_user WHERE dt = ‘2018-05-31’
;
额外延伸:
Hive 的CROSS JOIN :
Hive 中的CROSS JOIN ,为笛卡尔积。除非特殊需求,并且数据量不是特比的大的情况下,才可以慎用CROSS JOIN 。否则。很难跑出正确的结果,或者JOB 压根不能执行完。
Hive 中的连接
优化技巧:
Hive 中JOIN 的关键键必须在 ON() 中指定,不能在WHERE 中指定,否则就会先做笛卡尔积,再过滤
Hive 的ROW_NUMBER() OVER()
参考文章 :https://blog.csdn.net/u010003835/article/details/88179677
ROW_NUMBER() OVER ([partition BY COLUMN_A] ORDER BY COLUMN_B ASC/DESC)
这个函数主要是用来分组排序的, 当不指定分组条件,则按照顺序递增
相关SQL :
建表构建数据:
CREATE TABLE IF NOT EXISTS tmp_S1 (
id BIGINT
,name STRING
,note STRING
) PARTITIONED BY (
pt STRING
);
INSERT INTO TABLE tmp_S1 PARTITION (pt = '20190601')
VALUES (1, 's1-haha', 'CC'), (2, 's1-zk', 'CC');
CREATE TABLE IF NOT EXISTS tmp_S2 (
id BIGINT
,name STRING
,note STRING
) PARTITIONED BY (
pt STRING
);
INSERT INTO TABLE tmp_S2 PARTITION (pt = '20190601')
VALUES (1, 's2-cx', 'CC'), (2, 's2-zk', 'CC');
从数据源导入增量表 ( 包含增量表建表语句)
CREATE TABLE IF NOT EXISTS tmp_S_inc (
id BIGINT
,name STRING
,note STRING
,source STRING
) PARTITIONED BY (
pt STRING
);
INSERT OVERWRITE TABLE tmp_S_inc PARTITION (pt = '20190601')
SELECT
tmp_s1.id
,tmp_s1.name
,tmp_s1.note
,'S1' AS source
FROM tmp_s1
WHERE pt = '20190601'
UNION ALL
SELECT
tmp_s2.id
,tmp_s2.name
,tmp_s2.note
,'S2' AS source
FROM tmp_s2
WHERE pt = '20190601'
;
从增量表导入目标表(包含目标表建表语句)
CREATE TABLE IF NOT EXISTS tmp_dim_S
(
uid BIGINT,
id BIGINT,
name STRING,
note STRING,
source STRING
)
PARTITIONED BY
(
pt STRING
);
-- SELECT COALESCE(MAX(uid), 0)
-- FROM tmp_dim_s
-- WHERE pt = '20190531'
-- ;
INSERT OVERWRITE TABLE tmp_dim_S PARTITION (pt = '20190601')
SELECT
(ROW_NUMBER() OVER(ORDER BY ta.id) + max_uid) AS uid
,ta.*
FROM (
SELECT
id
,name
,note
,source
FROM tmp_S_inc
WHERE pt = '20190601'
) AS ta
CROSS JOIN (
SELECT COALESCE(MAX(uid), 0) AS max_uid
FROM tmp_dim_S
WHERE pt = '20190531'
) AS tb
UNION ALL
SELECT
tmp_dim_S.uid
,tmp_dim_S.id
,tmp_dim_S.name
,tmp_dim_S.note
,tmp_dim_S.source
FROM tmp_dim_S
WHERE pt = '20190531'
;