Spark的textFile与wholeTextFiles比较

17

我了解textFile基本原理,它可以为每个文件生成分区;而wholeTextFiles则会生成一组键值对的RDD(Resilient Distributed Datasets),其中键是每个文件的路径,值是每个文件的内容。

现在,从技术角度来看,这两者有什么区别:

val textFile = sc.textFile("my/path/*.csv", 8)
textFile.getNumPartitions
val textFile = sc.wholeTextFiles("my/path/*.csv",8)
textFile.getNumPartitions
在这两种方法中,我都生成了8个分区。那么为什么我应该首先使用wholeTextFiles,它相对于textFile有什么好处呢?

在这两种方法中,我都生成了8个分区。那么为什么我应该首先使用wholeTextFiles,它相对于textFile有什么好处呢?

5个回答

31

正如您所提到的,主要区别在于textFile会返回一个RDD,其中每行都是一个元素,而wholeTextFiles则返回一个PairRDD,其键为文件路径。如果不需要根据文件分隔数据,则直接使用textFile即可。

使用textFile读取未压缩文件时,它将把数据拆分成32MB的块。这从内存角度来看是有优势的。这也意味着行的顺序会丢失,如果需要保留顺序,则应该使用wholeTextFiles

wholeTextFiles将一次性读取文件的所有内容,不会部分地溢出到磁盘或部分垃圾回收。每个文件将由一个核心处理,并且每个文件的数据将位于单个机器上,这使得难以分配负载。


31

textFile函数将每个文件生成一个分区,而wholeTextFiles函数生成一对值的RDD。

这个说法不准确:

  1. textFile函数加载一个或多个文件,每个作为产生的RDD中的一个记录。如果文件足够大(取决于请求的分区数量、Spark的默认分区数量和底层文件系统),单个文件可能会被拆分成多个分区。当同时加载多个文件时,该操作将“丢失”记录和包含它的文件之间的关系——即无法知道哪个文件包含了哪一行。RDD中的记录顺序将遵循文件名称的字母顺序以及文件内部记录的顺序(顺序不会“丢失”)。

  2. wholeTextFiles函数通过将数据加载到一个PairRDD中,每个输入文件生成一个记录,保留了数据和包含它的文件之间的关系。该记录的形式为(fileName, fileContent)。这意味着加载大文件是有风险的(可能会导致性能下降或OutOfMemoryError,因为每个文件必须存储在一个节点上)。基于用户输入或Spark的配置,将多个文件加载到一个分区中。

一般来说,textFile函数适用于仅需要加载大量数据的常见用例(不考虑如何将其拆分为文件)。只有在实际需要知道每个记录的来源文件名称,并且您知道所有文件都足够小的情况下,才应使用wholeTextFiles函数。


1
这似乎是更准确的答案。 - Michael Wu

3
从Spark2.1.1开始,以下是textFile的代码示例。
def textFile(
  path: String,
  minPartitions: Int = defaultMinPartitions): RDD[String] = withScope {
assertNotStopped()

hadoopFile(path, classOf[TextInputFormat], classOf[LongWritable], classOf[Text],
  minPartitions).map(pair => pair._2.toString).setName(path)  }

使用hadoopFile读取本地文件、HDFS文件和S3的内部实现采用以下模式:file://hdfs://s3a://

而WholeTextFile的语法如下:

def wholeTextFiles(
  path: String,
  minPartitions: Int = defaultMinPartitions): RDD[(String, String)] = withScope 

如果我们观察这两种方法的语法是相等的,但是 textfile 用于读取文件,而 wholeTextFiles 用于读取小文件目录。 但是我们也可以使用较大的文件,但性能可能会受到影响。
因此,当您想处理大文件时,textFile 是更好的选择,而如果我们想处理小文件目录,则使用 wholeTextFile 更好。

2
  1. textfile()函数读取文本文件并返回一个字符串类型的RDD。例如,sc.textFile("/mydata.txt")将创建一个RDD,其中每一行都是一个元素。

  2. wholeTextFile()函数读取文本文件目录并返回一个pairRDD。 例如,如果目录中有几个文件,则wholeTextFile()方法将创建一个键为文件名和路径、值为整个文件的字符串的pair RDD。


0
请看下面的示例以获得更清晰的理解:
textFile = sc.textFile("ml-100k/u1.data")
textFile.getNumPartitions()

输出- 2
即2个分区

textFile = sc.wholeTextFiles("ml-100k/u1.data")
textFile.getNumPartitions()

输出 - 1
即仅有一个分区。

所以简而言之,wholeTextFiles

从HDFS、本地文件系统(所有节点都可用)或任何Hadoop支持的文件系统URI中读取一组文本文件的目录。每个文件作为单个记录进行读取,并以键值对的形式返回,其中键是每个文件的路径,值是每个文件的内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接