在Scala中使用SparkContext.sequenceFile(...)。foreach的范围问题

时间:2017-05-24 14:56:13

标签: scala apache-spark

我的目标是处理通过调用SequenceFile生成的一系列org.apache.spark.rdd.RDD[_].saveAsObjectFile(...)个文件夹。我的文件夹结构类似于:

\MyRootDirectory
  \Batch0001
     _SUCCESS
     part-00000
     part-00001
     ...
     part-nnnnn
  \Batch0002
     _SUCCESS
     part-00000
     part-00001
     ...
     part-nnnnn
  ...
  \Batchnnnn
     _SUCCESS
     part-00000
     part-00001
     ...
     part-nnnnn

我需要提取一些持久化数据,但是我的集合 - 无论是使用ListBuffermutable.Map还是任何其他可变类型,都会丢失范围并且似乎在每次迭代时都会被新建sequenceFile(...).foreach

以下概念证明会生成一系列“处理目录...”,然后重复“1:1”并且不会增加,正如我预期counterintList.size所做的那样。

  private def proofOfConcept(rootDirectoryName: String) = {
    val intList = ListBuffer[Int]()
    var counter: Int = 0
    val config = new SparkConf().setAppName("local").setMaster("local[1]")
    new File(rootDirectoryName).listFiles().map(_.toString).foreach { folderName =>
      println(s"Processing directory $folderName...")
      val sc = new SparkContext(config)
      sc.setLogLevel("WARN")
      sc.sequenceFile(folderName, classOf[NullWritable], classOf[BytesWritable]).foreach(f => {
        counter += 1
        intList += counter
        println(s"  $counter : ${intList.size}")
      })
      sc.stop()
    }
  }

输出:

"C:\Program Files\Java\jdk1.8.0_111\bin\java" ...
Processing directory C:\MyRootDirectory\Batch0001...
17/05/24 09:30:25.228 WARN  [main] org.apache.hadoop.util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
[Stage 0:>                                                         (0 + 0) / 57]  1 : 1
  1 : 1
  1 : 1
  1 : 1
  1 : 1
  1 : 1
  1 : 1
  1 : 1
Processing directory C:\MyRootDirectory\Batch0002...
  1 : 1
  1 : 1
  1 : 1
  1 : 1
  1 : 1
  1 : 1
  1 : 1
  1 : 1
Processing directory C:\MyRootDirectory\Batch0003...
  1 : 1
  1 : 1
  1 : 1
  1 : 1
  1 : 1
  1 : 1
  1 : 1
  1 : 1

1 个答案:

答案 0 :(得分:1)

foreach内的函数在spark worker JVM中运行,而不是在客户端JVM中运行,其中定义了变量。该worker在本地获取该变量的副本,递增它并打印它。我的猜测是你在本地进行测试吗?如果您在生产的分布式火花环境中运行它,您甚至看不到这些打印的输出。

更一般地说,几乎任何传递给RDD方法之一的函数都可能实际上是远程执行的,并且不会对任何局部变量或任何东西进行可变访问。它将获得一个基本上不可变的快照。

如果要将spark的分布式存储中的数据移回客户端,请使用RDD的collect方法。相反的是sc.parallelize。但请注意,这两种情况通常很少发生,因为它们不是并行发生的。