目录
本篇文章记录用户访问session分析-数据倾斜解决方案之使用随机key实现双重聚合。
使用随机key实现双重聚合
1、原理
第一次聚合(局部聚合):对每一个Key值加上一个随机数,执行第一次reduceByKey聚合操作。
第二次聚合(双重聚合):去掉Key值的前缀随机数,执行第二次reduceByKey聚合,最终得到全局聚合的结果。
2、使用场景
(1)groupByKey
(2)reduceByKey
比较适合使用这种方式;join,咱们通常不会这样来做,后面会讲三种,针对不同的join造成的数据倾斜的问题的解决方案。
第一轮聚合的时候,对key进行打散,将原先一样的key,变成不一样的key,相当于是将每个key分为多组;
先针对多个组,进行key的局部聚合;接着,再去除掉每个key的前缀,然后对所有的key,进行全局的聚合。
对groupByKey、reduceByKey造成的数据倾斜,有比较好的效果。
如果说,之前的第一、第二、第三种方案,都没法解决数据倾斜的问题,那么就只能依靠这一种方式了。
图解
代码
/** * 第一步,给每个key打上一个随机数 */ JavaPairRDD<String, Long> mappedClickCategoryIdRDD = clickCategoryIdRDD.mapToPair( new PairFunction<Tuple2<Long,Long>, String, Long>() { private static final long serialVersionUID = 1L; @Override public Tuple2<String, Long> call(Tuple2<Long, Long> tuple) throws Exception { Random random = new Random(); int prefix = random.nextInt(10); return new Tuple2<String, Long>(prefix + "_" + tuple._1, tuple._2); } }); /** * 第二步,执行第一轮局部聚合 */ JavaPairRDD<String, Long> firstAggrRDD = mappedClickCategoryIdRDD.reduceByKey( new Function2<Long, Long, Long>() { private static final long serialVersionUID = 1L; @Override public Long call(Long v1, Long v2) throws Exception { return v1 + v2; } }); /** * 第三步,去除掉每个key的前缀 */ JavaPairRDD<Long, Long> restoredRDD = firstAggrRDD.mapToPair( new PairFunction<Tuple2<String,Long>, Long, Long>() { private static final long serialVersionUID = 1L; @Override public Tuple2<Long, Long> call(Tuple2<String, Long> tuple) throws Exception { long categoryId = Long.valueOf(tuple._1.split("_")[1]); return new Tuple2<Long, Long>(categoryId, tuple._2); } }); /** * 第四步,最第二轮全局的聚合 */ JavaPairRDD<Long, Long> clickCategoryId2CountRDD = restoredRDD.reduceByKey( new Function2<Long, Long, Long>() { private static final long serialVersionUID = 1L; @Override public Long call(Long v1, Long v2) throws Exception { return v1 + v2; } });