spark RDD的aggregate(聚合)方法

首先来看一下aggregate方法的具体实现:

/**
   * Aggregate the elements of each partition, and then the results for all the partitions, using
   * given combine functions and a neutral "zero value". This function can return a different result
   * type, U, than the type of this RDD, T. Thus, we need one operation for merging a T into an U
   * and one operation for merging two U's, as in scala.TraversableOnce. Both of these functions are
   * allowed to modify and return their first argument instead of creating a new U to avoid memory
   * allocation.
   *
   * @param zeroValue the initial value for the accumulated result of each partition for the
   *                  `seqOp` operator, and also the initial value for the combine results from
   *                  different partitions for the `combOp` operator - this will typically be the
   *                  neutral element (e.g. `Nil` for list concatenation or `0` for summation)
   * @param seqOp an operator used to accumulate results within a partition
   * @param combOp an associative operator used to combine results from different partitions
   */
  def aggregate[U: ClassTag](zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U): U = withScope {
    // Clone the zero value since we will also be serializing it as part of tasks
    var jobResult = Utils.clone(zeroValue, sc.env.serializer.newInstance())
    val cleanSeqOp = sc.clean(seqOp)
    val cleanCombOp = sc.clean(combOp)
    val aggregatePartition = (it: Iterator[T]) => it.aggregate(zeroValue)(cleanSeqOp, cleanCombOp)
    val mergeResult = (index: Int, taskResult: U) => jobResult = combOp(jobResult, taskResult)
    sc.runJob(this, aggregatePartition, mergeResult)
    jobResult
  }

使用以下命令聚合每个分区的元素,然后聚合所有分区的结果
给定组合函数和一个中性的“零值”。这个函数可以返回不同的结果
类型U,而不是RDD的类型T。因此,我们需要一个操作来将T合并到U中
以及一个用于合并两个U的操作,如scala.可遍历一次。这两个函数都是
允许修改和返回它们的第一个参数,而不是创建一个新的U来避免内存
分配。

下面直接上例子:

def func1(index: Int, iter: Iterator[(Int)]) : Iterator[String] = {
  iter.toList.map(x => "[partID:" +  index + ", val: " + x + "]").iterator
}
val rdd1 = sc.parallelize(List(1,2,3,4,5,6,7,8,9), 2)
rdd1.mapPartitionsWithIndex(func).collect
rdd1.aggregate(0)(math.max(_, _), _ + _)
rdd1.aggregate(5)(math.max(_, _), _ + _)

运行截图:

在这里插入图片描述
这个方法是先聚合每个分区的元素,再聚合所有分区的结果。

括号中的0和5是初始值,当初始值为0的时候,先求出每个分区的最大值,再将两个分区的结果相加。
上面rdd1的分区分别是:

分区ID分区数据
01,2,3,4
15,6,7,8,9

第一个分区的最大值是4,第二个分区的最大值是9,再让4+9=13

当初始值为5时,第一个分区的最大值是4,然后拿着4和5进行比较,所以第一个分区的结果是5,第二个分区的最大值是9,拿着9和5进行比较,所以第二个分区的结果是9,最后是让5+5+9=19,聚合最终结果时会将初始值一起计算。

val rdd2 = sc.parallelize(List("a","b","c","d","e","f"),2)
rdd2.aggregate("")(_ + _, _ + _)
rdd2.aggregate("=")(_ + _, _ + _)

运行截图:
在这里插入图片描述
会得到不同的结果,是因为在执行计算的时候,会将数据进行切分,生成两个切片,然后就会生成两个task去执行,这两个task是并行执行的,所以会出现不同的结果。

在这里插入图片描述先进行切分,生成两个切片:

切片ID分区数据
0a,b,c
1d,e,f

生成两个task去并行执行,执行过程是:
1.第一个task去执行ID为0的数据(a,b,c),进行_+_操作,将a,b,c连接起来,生成abc,再拿着abc与=连接,最终生成=abc;
第二个task做同样的事情,最终生成=def。

2 两个分区都得到结果后,再执行后面的_+_操作,将两个分区的结果相加,得到=abc=def,然后再与初始值=相连接,得到最终结果==abc=def或者==def=abc

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值