Spark RDD聚合动作表现奇怪

时间:2016-06-29 13:23:47

标签: scala apache-spark

以下是代码:

  val email1 = sc.textFile("/Users/kaiyin/IdeaProjects/learnSpark/src/main/resources/ling-spam/ham/3-378msg3.txt")
  val email2 = sc.textFile("/Users/kaiyin/IdeaProjects/learnSpark/src/main/resources/ling-spam/ham/3-378msg4.txt")
  val email = email1 ++ email2
  println(s"Count check: ${email.count() == email1.count() + email2.count()}")
  val partitionLengths = email.aggregate(Vector.empty[Int])((vec, s) => s.length +: vec, (i1, i2) => i1 ++ i2)
  println(partitionLengths)
  println(partitionLengths.sum == email.map(_.length).sum)
  val partitionLengthsMax = email.aggregate(0)((i: Int, s: String) => {
    println(s"Partition length: ${s.length}")
    i + s.length
  }, (i1, i2) => i1.max(i2))
  println(partitionLengthsMax)

在repl中运行它会给出:

Count check: true
Vector(244, 0, 31, 96, 0, 23)
true
Partition length: 23
Partition length: 0
Partition length: 96
Partition length: 31
Partition length: 0
Partition length: 244
275

首先,为什么设置为local[4]时有6个分区? 为什么最大长度不是244?显然275 = 244 + 31.

完整的脚本可以在这里找到:https://github.com/kindlychung/learnSpark/blob/master/src/main/scala/RDDDemo.scala

2 个答案:

答案 0 :(得分:0)

  

为什么设置为本地时有6个分区[4]

请注意,如果rdd1包含x个分区,rdd2包含y个分区,rdd1 ++ rdd2将有x+y个分区。

  

为什么最大长度不是244?

您似乎认为aggregate的最后一个参数combOp: (U, U) ⇒ U仅用于合并单独分区的结果。嗯,事实并非如此:combOp也用于有效地聚合分区内的结果。

实际上,RDD.aggregate' implementation几乎如下:

  • 对于每个分区,请调用iterator.aggregate(zeroValue)(seqOp, compOb)来聚合该分区
  • 使用compOb将所有分区合并到一起

在第一步中,aggregate方法为GenTraversableOnce.aggregateScalaDocs明确指出:

  

此操作的实现可以在任意数量的集合分区上运行,因此combop可以被调用任意次数

底线 - compOp被称为每RDD分区多次,因此您将看到结果。

答案 1 :(得分:0)

我稍微修改了代码片段以查看中间结果

val partitionLengthsMax = email.aggregate(0)(
    (i: Int, s: String) => {
        println(s"$i Partition length: ${s.length} ${s.take(15)}")
        i + s.length
    }, 
    (i1, i2) => {
        println(s"$i1, $i2")
        i1.max(i2)
    })

根据Spark doc。代码段应该意味着获得子分区总和的最大大小。

def aggregate[U](zeroValue: U)(
    seqOp: (U, T) ⇒ U, 
    combOp: (U, U) ⇒ U)(implicit arg0: ClassTag[U]): U
  

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