Java 使用Spark API如何处理大型目录树?

Java 使用Spark API如何处理大型目录树?,java,scala,hadoop,apache-spark,Java,Scala,Hadoop,Apache Spark,我是一个新的Spark用户,我正在尝试处理HDFS文件系统上的一大组XML文件。在一台由1台机器(实际上是一台VM)组成的“开发”集群上,大约有150k个文件,总计约28GB 这些文件在HDFS中被组织成一个目录结构,这样在一个父目录下大约有100个子目录。每个“子”目录包含几百到几千个XML文件之间的任何内容 我的任务是解析每个XML文件,使用XPath表达式提取一些值,并将结果保存到HBase。我正试图用ApacheSpark实现这一点,但我运气不太好。我的问题似乎是Spark API和RD

我是一个新的Spark用户,我正在尝试处理HDFS文件系统上的一大组XML文件。在一台由1台机器(实际上是一台VM)组成的“开发”集群上,大约有150k个文件,总计约28GB

这些文件在HDFS中被组织成一个目录结构,这样在一个父目录下大约有100个子目录。每个“子”目录包含几百到几千个XML文件之间的任何内容

我的任务是解析每个XML文件,使用XPath表达式提取一些值,并将结果保存到HBase。我正试图用ApacheSpark实现这一点,但我运气不太好。我的问题似乎是Spark API和RDD工作方式的结合。在这一点上,分享一些伪代码来表达我的意图可能是明智的:

RDD[String] filePaths = getAllFilePaths()
RDD[Map<String,String>] parsedFiles = filePaths.map((filePath) => {
    // Load the file denoted by filePath
    // Parse the file and apply XPath expressions
})
// After calling map() above, I should have an RDD[Map<String,String>] where
// the map is keyed by a "label" for an xpath expression, and the
// corresponding value is the result of the expression applied to the file 
RDD[String]filepath=getAllFilePath()
RDD[Map]parsedFiles=filePath.Map((filePath)=>{
//加载由filePath表示的文件
//解析文件并应用XPath表达式
})
//在调用上面的map()之后,我应该有一个RDD[map],其中
//映射由xpath表达式的“标签”键控,而
//相应的值是应用于文件的表达式的结果
因此,暂且不谈我给HBase写的那部分内容,让我们把重点放在上面。我无法从RDD map()调用中加载文件

我尝试了许多不同的方法,但都失败了:

  • 使用to
    SparkContext.textFile(“/my/path”)
    加载文件失败,因为
    SparkContext
    不可序列化
  • 使用Hadoop API中的to
    FileSystem.open(path)
    ,其中在RDD外部实例化
    文件系统
    失败,因为
    文件系统
    不可序列化
  • 从Hadoop API调用
    FileSystem.open(path)
    ,其中在RDD内部实例化
    文件系统
    ,会失败,因为程序没有文件句柄 其他方法包括尝试使用
    SparkContext.wholeTextFiles(“/my/path/*”)
    ,这样我就不必从map()调用中加载文件,因为程序内存不足而失败。这大概是因为它急切地加载文件


    有人在自己的工作中尝试过类似的事情吗?如果是,您使用了什么方法?

    尝试使用通配符读取整个目录。
    
    val errorCount=sc.textFile(“hdfs://some-directory/*")
    

    实际上,spark可以读取整个hfs目录,引用spark的话

    Spark的所有基于文件的输入方法,包括textFile,都支持 在目录、压缩文件和通配符上运行。对于 例如,您可以使用
    textFile(“/my/directory”)
    textFile(“/my/directory/*.txt”)
    ,和
    textFile(“/my/directory/*.gz”)


    我认为
    wholeTextFiles
    是一条出路。只需添加更多内存。谢谢您的评论。不幸的是,我没有28GB的内存。当我拿到一个更大的文件集,比如说500GB而不是28 GB时,采用这种方法就会崩溃。不,
    wholeTextFiles
    只需要足够的内存来加载最大的文件。如果你有更多的文件,那很好,你不需要更多的内存。(每个执行器线程一次加载一个文件。您还可以限制执行器线程的数量,这样每个线程就有更多内存。)感谢您的回复。我已经考虑过了,但这是大约28GB的数据,超过150000个文件-如果该方法急切地将文件加载到RDD中,那么它将无法放入内存中。您可以根据这些文件的目录将其分为几个批吗?我的意思是,您可以将文件分为5或8个输入RDD,每次一个。顺便说一下,这不是RDD
    map()
    应该做的。我想我可以,但那必须通过编程来完成。你对map()的评论是什么意思?@Jon你所做的是在RDD之间,而不是在一个RDD内,所以这不是RDD的
    map()
    函数所能做的。
    sc.textFile
    将所有文件读入一个RDD,每个文件行有一个RDD行。您将无法知道每个文件的开始和结束位置。