如何从Spark执行器读取HDFS文件?

时间:2019-04-01 15:31:05

标签: scala apache-spark hadoop amazon-s3 hdfs

我有一个大(> 500m行)的CSV文件。 CSV文件中的每一行都包含指向HDFS上的二进制文件的路径。我想使用Spark读取每个文件,进行处理,然后将结果写到另一个CSV文件或表中。

在驱动程序中执行此操作非常简单,下面的代码即可完成工作

val hdfsFilePathList = // read paths from CSV, collect into list

hdfsFilePathList.map( pathToHdfsFile => {
  sqlContext.sparkContext.binaryFiles(pathToHdfsFile).mapPartitions { 
    functionToProcessBinaryFiles(_)
  }
})

与此有关的主要问题是驱动程序正在做太多的工作。我想将binaryFiles完成的工作分发给执行者。我找到了一些有希望的示例,我认为这些示例可以使我从执行程序访问sparkContext:

Use SparkContext hadoop configuration within RDD methods/closures, like foreachPartition

https://github.com/apache/spark/blob/master/core/src/main/scala/org/apache/spark/util/SerializableConfiguration.scala

但是它们似乎没有按照我认为的方式工作。我希望以下方法能起作用:

import java.io.{ObjectInputStream, ObjectOutputStream}
import org.apache.hadoop.fs.FileSystem
import org.apache.hadoop.conf.Configuration

class ConfigSerDeser(var conf: Configuration) extends Serializable {

  def this() {
    this(new Configuration())
  }

  def get(): Configuration = conf

  private def writeObject (out: java.io.ObjectOutputStream): Unit = {
    conf.write(out)
  }

  private def readObject (in: java.io.ObjectInputStream): Unit = {
    conf = new Configuration()
    conf.readFields(in)
  }

  private def readObjectNoData(): Unit = {
    conf = new Configuration()
  }
}

val serConf = new ConfigSerDeser(sc.hadoopConfiguration)

val mappedIn = inputDf.map( row => {
    serConf.get()
})

但是它失败并显示KryoException: java.util.ConcurrentModificationException

执行者是否可以直接访问HDFS文件或HDFS文件系统?或者,是否存在一种有效的方法来读取HDFS / S3上的数百万个二进制文件并使用Spark处理它们?

1 个答案:

答案 0 :(得分:0)

有一个类似的用例,我试图做同样的事情,但是意识到 SparkSession或SparkContext不可序列化,因此无法从执行程序访问。