Hive之——数据倾斜与解决方案

转载请注明出处:https://blog.csdn.net/l1028386804/article/details/80165054

1、空值数据倾斜

场景: 如日志中,常会有信息丢失的问题,比如全网日志中的 user_id,如果取其中的 user_id和 bmw_users 关联,会碰到数据倾斜的问题。
解决方法 1: user_id 为空的不参与关联

Select * From log a
Join bmw_users b
On a.user_id is not null
And a.user_id = b.user_id
Union all
Select * from log a
where a.user_id is null;
解决方法 2: 赋与空值分新的 key 值
Select *
from log a
left outer join bmw_users b
on case when a.user_id is null then concat(‘dp_hive’,rand() ) else a.user_id = b.user_id end;
结论: 方法2比方法1效率更好,不但 io 少了,而且作业数也少了。方法 1 log 读取两次, jobs是 2。方法 2 job 数是 1 。这个优化适合无效 id(比如-99,’’,null 等)产生的倾斜问题。把空值的 key 变成一个字符串加上随机数,就能把倾斜的数据分到不同的 reduce 上 ,解决数据倾斜问题。附上 hadoop 通用关联的实现方法(关联通过二次排序实现的,关联的列为 parition key,关联的列 c1 和表的 tag 组成排序的 group key,根据parition key分配reduce。同一reduce内根据 group key 排序)。

2、不同数据类型关联产生数据倾斜

场景: 一张表 s8 的日志,每个商品一条记录,要和商品表关联。但关联却碰到倾斜的问题。 s8 的日志中有字符串商品 id,也有数字的商品 id,类型是 string的,但商品中的数字 id 是 bigint 的。猜测问题的原因是把 s8 的商品 id 转成数字 id 做 hash 来分配 reduce,所以字符串 id 的 s8 日志,都到一个 reduce 上了,解决的方法验证了这个猜测。
解决方法: 把数字类型转换成字符串类型
Select * from s8_log a
Left outer join r_auction_auctions b
On a.auction_id = cast(b.auction_id as string);

3、大表 Join 的数据偏斜

MapReduce 编程模型下开发代码需要考虑数据偏斜的问题, Hive 代码也是一样。数据偏斜的原因包括以下两点:
  1. Map 输出 key 数量极少,导致 reduce 端退化为单机作业。
  2. Map 输出 key 分布不均,少量 key 对应大量 value,导致 reduce 端单机瓶颈。
Hive 中我们使用 MapJoin 解决数据偏斜的问题,即将其中的某个表(全量)分发到所有Map 端进行 Join,从而避免了 reduce。这要求分发的表可以被全量载入内存。极限情况下, Join 两边的表都是大表,就无法使用 MapJoin。这种问题最为棘手,目前已知的解决思路有两种:
1) 如果是上述情况 1,考虑先对 Join 中的一个表去重,以此结果过滤无用信息。这样一般会将其中一个大表转化为小表,再使用 MapJoin 。
一个实例是广告投放效果分析,例如将广告投放者信息表 i 中的信息填充到广告曝光日志表 w 中,使用投放者 id 关联。因为实际广告投放者数量很少(但是投放者信息表 i 很大),因此可以考虑先在 w 表中去重查询所有实际广告投放者 id 列表,以此 Join 过滤表 i,这一结果必然是一个小表,就可以使用 MapJoin。
2) 如果是上述情况 2,考虑切分 Join 中的一个表为多片,以便将切片全部载入内存,然后采用多次 MapJoin 得到结果。一个实例是商品浏览日志分析,例如将商品信息表 i 中的信息填充到商品浏览日志表w中,使用商品 id 关联。但是某些热卖商品浏览量很大,造成数据偏斜。例如,以下语句实现了一个 inner join 逻辑,将商品信息表拆分成 2 个表:
select * from
(
select w.id, w.time, w.amount, i1.name, i1.loc, i1.cat
from w left outer join i sampletable(1 out of 2 on id) i1
)
union all
(
select w.id, w.time, w.amount, i2.name, i2.loc, i2.cat
from w left outer join i sampletable(1 out of 2 on id) i2
) )
;
以下语句实现了 left outer join 逻辑:
select t1.id, t1.time, t1.amount,
coalease(t1.name, t2.name),
coalease(t1.loc, t2.loc),
coalease(t1.cat, t2.cat)
from (
select w.id, w.time, w.amount, i1.name, i1.loc, i1.cat
from w left outer join i sampletable(1 out of 2 on id) i1
) t1 left outer join i sampletable(2 out of 2 on id) t2;
上述语句使用 Hive 的 sample table 特性对表做切分。


你可能感兴趣的:(Hive,Hadoop生态)