Spark 算子aggregateByKey理解

前言:

看了一大堆网上的介绍没看明白aggregateByKey到底啥意思,自己琢磨半天,感觉知道到底如何用了,特意写出来分享下。

准备:

用java写aggregateByKey,这样好理解一点

算子释义:

aggregateByKey, 先说分为三个参数的:
第一个参数是, 每个key的初始值
第二个是个函数, Seq Function, 经测试这个函数就是用来先对每个分区内的数据按照key分别进行定义进行函数定义的操作
第三个是个函数, Combiner Function, 对经过 Seq Function 处理过的数据按照key分别进行进行函数定义的操作

测试代码如下:

List<Tuple2<String, Integer>> abk = Arrays.asList(
        new Tuple2<String, Integer>("class1", 1),
        new Tuple2<String, Integer>("class1", 2),
        new Tuple2<String, Integer>("class1", 4),
        new Tuple2<String, Integer>("class2", 3),
        new Tuple2<String, Integer>("class2", 1),
        new Tuple2<String, Integer>("class2", 5));
JavaPairRDD<String, Integer> abkrdd = js.parallelizePairs(abk, 3);
abkrdd.mapPartitionsWithIndex(
        new Function2<Integer, Iterator<Tuple2<String, Integer>>, Iterator<String>>() {
            @Override
            public Iterator<String> call(Integer s,
                    Iterator<Tuple2<String, Integer>> v)
                    throws Exception {
                List<String> li = new ArrayList<>();
                while (v.hasNext()) {
                    li.add("data:" + v.next() + " in " + (s + 1) + " " + " partition");
                }
                return li.iterator();
            }
        }, true).foreach(m -> System.out.println(m));
JavaPairRDD<String, Integer> abkrdd2 = abkrdd.aggregateByKey(0,
        new Function2<Integer, Integer, Integer>() {
            @Override
            public Integer call(Integer s, Integer v) throws Exception {
                System.out.println("seq:" + s + "," + v);
                return Math.max(s, v);
            }
        }, new Function2<Integer, Integer, Integer>() {
            @Override
            public Integer call(Integer s, Integer v) throws Exception {
                System.out.println("com:" + s + "," + v);
                return s + v;
            }
        });

abkrdd2.foreach(new VoidFunction<Tuple2<String, Integer>>() {
    @Override
    public void call(Tuple2<String, Integer> s) throws Exception {
        System.out.println("c:" + s._1 + ",v:" + s._2);
    }
});

过程分析:

1)输出结果如下:

2)初始数据转为rdd时设置了三个分区,通过mapPartitionWithIndex输出各个数据所在分区如下:

对于partition 1,有数据(class1,1),(class1,2)

对于partition 2,有数据(class1,4),(class2,3)

对于partition 2,有数据(class2,1),(class2,5)

3)然后对rdd进行aggregateByKey操作:

设置第一个参数:初始对比值为0,注意0只会在Seq Function(也就是第二个参数)中使用,若是aggregate算子,在Combiner Function 中也会被使用

设置第二个参数:Seq Function,对每个分区内的数据按照key分别进行定义进行函数定义的操作。

设置第三个参数:Combiner Function, 对经过 Seq Function 处理过的数据按照key分别进行函数定义的操作

4)分析如下:

对于partition 1,先进行Seq Function定义的操作(取最大值):由于key值都是class1,所以过程如下:

data:(class1,1),(class1,2)

key:class1

0 对比1 -> 1 

1 对比2 -> 2

故该分区key值对应的最终结果为:(class1,2)

对于partition 2,同上,先进行Seq Function定义的操作(取最大值):但是由于该分区内key值不同,所以过程略有不同,跟上面上比:

data:(class1,4),(class2,3)

key:class1

0 对比4 -> 4

key:class2

0 对比3 -> 3

故该分区key值对应的最终结果为:(class1,4),(class2,3)

注:这块测试一下午,源码一大堆调用看不懂,然后就纳闷到底为啥,我刚开始的时候以为:只要是一个分区内的数据,互相之间都要进行对比,然后看执行流程就是不明白为啥class1的4不给class2的3对比,而是用设置的初始值0去对比,一直以为是分区的问题,感觉(class1,4),(class2,3)不在一个分区,后来特意输出分区,发现确实它俩是在一个分区的,后来就怀疑是不是aggregateByKey即使不使用带分区的有4个参数的那种模式,分区参数也会有个默认值,然后我就去设置了一个分区值,发现并没有影响,还是这种情况,4就是不跟3比,我就不懂了,到底为啥,然后我就出去逛了一会,再回来做到电脑面前,突然福至心灵,悟了,就是如上这个函数就是用来先对每个分区内的数据按照key分别进行定义进行函数定义的操作。做了一些小测试如下:加上一个数据(class3,4),结果如下:

证实了我的想法。

对于partition 3,同上:过程如下:

data:(class2,1),(class2,5)

key:class2

0 对比1 -> 1 

1 对比5 -> 5

故该分区key值对应的最终结果为:(class2,5)

然后来到第三个参数所定义的函数:Combiner Function,这个函数是针对的所有分区的数据,按照key分别进行Combiner Function定义的相加操作:

上一步出来的最终结果如下:

partition1:(class1,2)

partition2:(class1,4),(class2,3)

partition3:(class2,5)

然后进行Combiner Function定义的操作:

key:class1

2 + 4  ->   6

然后foreach输出如下:

key:class2

3 + 5 -> 8

然后foreach输出如下:

 

疑惑:不知道aggregateByKey的分区参数到底有啥用?

 

def aggregateByKey[U: ClassTag](zeroValue: U, numPartitions: Int)

    (seqOp: (U, V) => U, combOp: (U, U) => U): RDD[(K, U)]

以为是重新设定分区,但是尝试后发现,并不是,不知道有啥用,难道是重新分配task任务数??不清楚呀

后记:重分区,这块评论区已解决;好久不编程了,这块都忘得差不多了,感谢评论区的小伙伴。

 

 


 

 

 

 

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值