Spark mapPartitions中的执行顺序

时间:2017-11-22 04:22:05

标签: scala apache-spark iterator

当我使用Spark mapPatartitions时遇到了一些奇怪的东西,创建的mutable.HashSet无法在map进程中正确填充,这里是代码:

object Test {
  def main(args: Array[String]) {
    val conf = new SparkConf().setAppName("Test").setMaster("local")
    val sc = new SparkContext(conf)
    val input = List[String]("1", "2", "3", "3", "4", "5", "5")
    val result = sc.parallelize(input)
      .mapPartitions((pi: Iterator[String]) => {
        val valuesInPartition = new mutable.HashSet[String]()
        val values = pi.map(line => {
          valuesInPartition.add(line)
          println("processing line: " + line + ", valuesInPartition: " + valuesInPartition)
        })
        println("valuesInPartition: " + valuesInPartition)
        values
      })
    result.collect
  }
}

和输出:

valuesInPartition: Set()
processing line: 1, valuesInPartition: Set(1)
processing line: 2, valuesInPartition: Set(1, 2)
processing line: 3, valuesInPartition: Set(3, 1, 2)
processing line: 3, valuesInPartition: Set(3, 1, 2)
processing line: 4, valuesInPartition: Set(3, 4, 1, 2)
processing line: 5, valuesInPartition: Set(3, 4, 1, 5, 2)
processing line: 5, valuesInPartition: Set(3, 4, 1, 5, 2)

但是据我所知,mapPartition中的代码应该按顺序执行,它应该在" map"之后打印最后一行。功能完成。但是这里的Set打印出来没有填充值。

我想我在这里理解错了,请帮我指出。

1 个答案:

答案 0 :(得分:4)

这与Spark无关 - 误解是关于Iteratormap方法的语义。请记住,Iterator是一种一次遍历一个元素的方法。调用pi.map(line => ...)会产生另一个Iterator - 但只有在请求该元素时才会感觉到生成Iterator的每个元素所涉及的副作用。

考虑以下(普通的旧Scala)REPL交互:

scala> val l1 = List(1,2,3,4,5)
l1: List[Int] = List(1, 2, 3, 4, 5)

scala> val l2 = l1.map(println)
1
2
3
4
5
l2: List[Unit] = List((), (), (), (), ())

scala> val i1 = Iterator(1,2,3,4,5)
i1: Iterator[Int] = non-empty iterator

scala> val i2 = i1.map(println)         // Look Ma, nothing happened!!
i2: Iterator[Unit] = non-empty iterator

scala> i2.next                          // Request the first element...
1

scala> i2.next                          // Request the second element...
2

scala> val l3 = i2.toList               // Request remaining elements.
3
4
5
l3: List[Unit] = List((), (), ())

在您的情况下,Iterator中存储的values仅在退出匿名函数后遍历(因此在println("valuesInPartition: " + valuesInPartition)之后)。