spark aggregateByKey算子

本文详细介绍了Spark中AggregateByKey算子的工作原理及其实现过程。通过具体的Java代码示例,展示了如何使用AggregateByKey算子对RDD进行聚合操作,并分析了不同分区数量下seqOp和combOp的具体作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

aggregateByKey算子的作用是根据key进行聚合操作,代码均是基于java api,先贴代码:

public class AggregateByKeyOperator {

   public static void main(String[] args) {
      SparkConf sparkConf = new SparkConf().setAppName("AggregateOperator")
            .setMaster("local[*]");
      JavaSparkContext sc = new JavaSparkContext(sparkConf);
      List<Tuple2<Integer,Integer>> dataList =  new ArrayList<Tuple2<Integer,Integer>>();
      dataList.add(new Tuple2<Integer, Integer>(1,99));
      dataList.add(new Tuple2<Integer, Integer>(2,78));
      dataList.add(new Tuple2<Integer, Integer>(1,89));
      dataList.add(new Tuple2<Integer, Integer>(2,3));
      dataList.add(new Tuple2<Integer, Integer>(3,3));
      dataList.add(new Tuple2<Integer, Integer>(3,30));
     
      JavaPairRDD<Integer, Integer> dataRdd = sc.parallelizePairs(dataList,1);
      System.out.println("dataRdd.partitions().size():"+dataRdd.partitions().size());
    //用于打印每个分区中的数据
    dataRdd.mapPartitionsWithIndex(new Function2<Integer, Iterator<Tuple2<Integer, Integer>>, Iterator<Tuple2<Integer, Integer>>>() {
         @Override
         public Iterator<Tuple2<Integer, Integer>> call(Integer index, Iterator<Tuple2<Integer, Integer>> t) throws Exception {
            System.out.println("partitionId:"+index);
            while(t.hasNext()) {
               Tuple2 t2 = t.next();
               System.out.println(t2._1+" "+t2._2);
            }
            return t;
         }
      },true).count();
      
      JavaPairRDD<Integer, Integer> aggregateByKey = dataRdd.aggregateByKey(0,new Function2<Integer, Integer, Integer>() {

         private static final long serialVersionUID = 1L;
         @Override
    //seqOp
         public Integer call(Integer t1, Integer t2) throws Exception {
            System.out.println("seq: " + t1 + "\t " + t2);
            return Math.max(t1, t2);
         }
      },new Function2<Integer, Integer, Integer>() {
    //combOp
         private static final long serialVersionUID = 1L;
         @Override
         public Integer call(Integer t1, Integer t2) throws Exception {
            System.out.println("comb: " + t1 + "\t " + t2);
            return t1+t2;
         }
      });

      List<Tuple2<Integer,Integer>> resultRdd = aggregateByKey.collect();
       for (Tuple2<Integer, Integer> tuple2 : resultRdd) {
         System.out.println(tuple2._1+"\t"+tuple2._2);
      }
   }
}

当RDD为一个分区的时候,根据key的不同,可以分为:

key=1: (1,99),(1,89)

key=2: (2,78),(2,3)

key=3:(3,3),(3,30)

这3个组分别进行seqOp,也就是(K,V)里面的V和0进行math.max()运算,运算结果和下一个V继续运算,运算过程是这样的:

key=1:  0,99 =>99,99,89 => 99

key=2:  0,78 => 78,78,3 =>78

key=3: 0,3 =>3,3,30=>30

最终结果是(1,99),(3,30),(2,78)  combOp是把不同分区相同的key的V加起来,由于这里并没有分区,所以实际上是不起作用的,计算结果如下:

(1 99)
(3 30)

(2 78)

如果将代码修改为:

JavaPairRDD<Integer, Integer> dataRdd = sc.parallelizePairs(dataList,2);
即指定2个分区,此时分区0的数据为:

1 99
2 78

1 89

分区1的数据为:

2 3
3 3

3 30

则进行seqOp操作时,只需要每个分区内部进行,

seqOp操作后结果,分区0:(1,99),(2,78)   分区1:(2,3),(3,30),根据上面的分析,combOp操作后的最终结果为:

(1,99),(2,81),(3,30)

同理,将分区数修改为3:,三个分区的数据分别为:

partitionId1 :
1 89
2 3
partitionId0 :
1 99
2 78
partitionId2 :
3 3

3 30

seqOp操作后结果为,分区0:(1,99),(2,78),分区1:(1,89),(2,3),分区2:(3,30),则combOp操作后的最终结果为:

(1,188),(2,81),(3,30)


最后总结一下:

aggregateByKey(p1,p2,p3)算子中,p1,p2,p3三个参数,p1为p2中进行比较的初始值,p2中的逻辑是对每一个分区中的key-value键值对进行操作,在本例中是筛选出每一个分区中key对应的最大的value ,p3的逻辑是对不同分区中p2得到的结果进行累加,若只有一个分区,p3无效。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值