转载请注明出处:https://blog.csdn.net/l1028386804/article/details/80165054
场景: 如日志中,常会有信息丢失的问题,比如全网日志中的 user_id,如果取其中的 user_id和 bmw_users 关联,会碰到数据倾斜的问题。
解决方法 1: user_id 为空的不参与关联
结论: 方法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 排序)。
场景: 一张表 s8 的日志,每个商品一条记录,要和商品表关联。但关联却碰到倾斜的问题。 s8 的日志中有字符串商品 id,也有数字的商品 id,类型是 string的,但商品中的数字 id 是 bigint 的。猜测问题的原因是把 s8 的商品 id 转成数字 id 做 hash 来分配 reduce,所以字符串 id 的 s8 日志,都到一个 reduce 上了,解决的方法验证了这个猜测。
解决方法: 把数字类型转换成字符串类型
MapReduce 编程模型下开发代码需要考虑数据偏斜的问题, Hive 代码也是一样。数据偏斜的原因包括以下两点:
Map 输出 key 数量极少,导致 reduce 端退化为单机作业。
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 个表:
以下语句实现了 left outer join 逻辑:
上述语句使用 Hive 的 sample table 特性对表做切分。