sparksql处理数据倾斜问题常见思路

假设spark中存在这样的一张存放着用户粉丝数的表 user_fan,字段为用户id–userId,粉丝id --fanId,现在要求出每个用户的粉丝数目,我们有以下的sql:

select userId,count(1) as cnt from user_fan group by userId

我们知道用户的粉丝数目是不均匀的,有些用户拥有上千万粉丝,而有些用户只有几十粉丝,这样一个sql带来的结果就是数据量大的分区的task花费很长时间,而数据量小的分区只需要花费很短的时间,当然如果每个task分区的时候恰巧能够分的均匀,比如A,B用户有100w粉丝,C,D用户有10个粉丝,如果分区时A和C用户分到同一个分区,B和D用户分到同一个分区,那么此时不会产生问题,但是这只是巧合,大部分情况下,分区时按照文件大小分区的,他不会理会业务的含义,所以这就造成了A,B,C在同一个分区,D在另一个分区,这样数据就会非常不均匀,所以我们这里能做的就是尽量让每个分区更加均匀,那怎么做到呢,我们知道按照用户维度来分组,肯定是不能达到目的的,那怎么做呢?

我们要做的就是分而治之的方法:
实现一:

select userId,count(1) as cnt from
(select userId,fanMod,count(1) as ufcnt from
(select userId,fanId,fanId % 10 as fanMod from user_fan) as a group by userId,fanMod) as b group by userId

先按照userId + fanMod的方式分组,其中fanMod我们可以取10或者100等,这样基于userid+fanMod的分组方式每一组数据就差不多均匀了,这样第一阶段得到userId+fanMod对应的count表的各个task运行时间就是均匀的,可以充分利用并行cpu加速.然后第二阶段再获取userId对应的count表,在这一个阶段中对于有大量粉丝的用户来说对应的fanMod数量也就是比如就是10或者100,对于小粉丝的用户来说可能就是1,但是由于这个数量差距很小(不会有类似之前sql用户粉丝间上百万的差距),所以第二阶段的task运行时速度不会相差很大,这样就达到了分而治之的目的.

实现二:
实现二的思路是先把用户粉丝大的记录分成一组,粉丝数量小的用户记录分成另一组,当前前提是你提前知道哪些用户的粉丝数量大,哪些用户的粉丝数量比较小,当然数量不需要太精确,然后对于每一组聚合求每个用户的粉丝数量,由于在每一组中每个用户的粉丝数量都在一个量级上,所以不会导致数据量的倾斜,这样每个组都获取到结果之后再把每一组的结果合并起来得到最终的结果.

--大粉丝组
select userId,count(1) as cnt from user_fan where user in (大粉丝组) group by userId
union
--小粉丝组
select userId,count(1) as cnt from user_fan where user in (小粉丝组) group by userId
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值