我想从hdfs位置读取一堆文本文件,并使用spark在迭代中对其执行映射。
JavaRDD<String> records = ctx.textFile(args[1], 1);
一次只能读取一个文件。
我想读取多个文件并将它们作为单个RDD处理。怎么样?
答案 0 :(得分:274)
您可以指定整个目录,使用通配符甚至CSV目录和通配符。 E.g:
sc.textFile("/my/dir1,/my/paths/part-00[0-5]*,/another/dir,/a/specific/file")
正如Nick Chammas所指出的,这是Hadoop FileInputFormat
的曝光,因此这也适用于Hadoop(和Scalding)。
答案 1 :(得分:31)
使用union
,如下所示:
val sc = new SparkContext(...)
val r1 = sc.textFile("xxx1")
val r2 = sc.textFile("xxx2")
...
val rdds = Seq(r1, r2, ...)
val bigRdd = sc.union(rdds)
然后bigRdd
是包含所有文件的RDD。
答案 2 :(得分:26)
您可以使用单个textFile调用来读取多个文件。阶:
sc.textFile(','.join(files))
答案 3 :(得分:8)
您可以使用此
首先,您可以获得S3路径的缓冲区/列表:
import scala.collection.JavaConverters._
import java.util.ArrayList
import com.amazonaws.services.s3.AmazonS3Client
import com.amazonaws.services.s3.model.ObjectListing
import com.amazonaws.services.s3.model.S3ObjectSummary
import com.amazonaws.services.s3.model.ListObjectsRequest
def listFiles(s3_bucket:String, base_prefix : String) = {
var files = new ArrayList[String]
//S3 Client and List Object Request
var s3Client = new AmazonS3Client();
var objectListing: ObjectListing = null;
var listObjectsRequest = new ListObjectsRequest();
//Your S3 Bucket
listObjectsRequest.setBucketName(s3_bucket)
//Your Folder path or Prefix
listObjectsRequest.setPrefix(base_prefix)
//Adding s3:// to the paths and adding to a list
do {
objectListing = s3Client.listObjects(listObjectsRequest);
for (objectSummary <- objectListing.getObjectSummaries().asScala) {
files.add("s3://" + s3_bucket + "/" + objectSummary.getKey());
}
listObjectsRequest.setMarker(objectListing.getNextMarker());
} while (objectListing.isTruncated());
//Removing Base Directory Name
files.remove(0)
//Creating a Scala List for same
files.asScala
}
现在将此List对象传递给以下代码段,注意:sc是SQLContext的对象
var df: DataFrame = null;
for (file <- files) {
val fileDf= sc.textFile(file)
if (df!= null) {
df= df.unionAll(fileDf)
} else {
df= fileDf
}
}
现在你有一个最终的统一RDD,即df
可选,您也可以在一个BigRDD
中重新分区val files = sc.textFile(filename, 1).repartition(1)
重新分区始终有效:D
答案 4 :(得分:3)
在PySpark中,我找到了另一种解析文件的有用方法。也许在Scala中有一个等价物,但我不太满意于提出一个有效的翻译。它实际上是一个带有标签的textFile调用(在下面的例子中,key = filename,value =来自文件的1行)。
“标签”textFile
输入:
import glob
from pyspark import SparkContext
SparkContext.stop(sc)
sc = SparkContext("local","example") # if running locally
sqlContext = SQLContext(sc)
for filename in glob.glob(Data_File + "/*"):
Spark_Full += sc.textFile(filename).keyBy(lambda x: filename)
output:数组,每个条目包含一个使用filename-as-key并且value =每行文件的元组。 (从技术上讲,使用此方法,您还可以使用除实际文件路径名称之外的其他键 - 可能是哈希表示以节省内存)。即。
[('/home/folder_with_text_files/file1.txt', 'file1_contents_line1'),
('/home/folder_with_text_files/file1.txt', 'file1_contents_line2'),
('/home/folder_with_text_files/file1.txt', 'file1_contents_line3'),
('/home/folder_with_text_files/file2.txt', 'file2_contents_line1'),
...]
您还可以重新组合作为一系列行:
Spark_Full.groupByKey().map(lambda x: (x[0], list(x[1]))).collect()
[('/home/folder_with_text_files/file1.txt', ['file1_contents_line1', 'file1_contents_line2','file1_contents_line3']),
('/home/folder_with_text_files/file2.txt', ['file2_contents_line1'])]
或者将整个文件重新组合回单个字符串(在此示例中,结果与从wholeTextFiles获得的结果相同,但是从文件路径中删除字符串“file:”。):
Spark_Full.groupByKey().map(lambda x: (x[0], ' '.join(list(x[1])))).collect()
答案 5 :(得分:3)
你可以使用
JavaRDD<String , String> records = sc.wholeTextFiles("path of your directory")
在这里,您将获得文件的路径和该文件的内容。所以你可以一次执行整个文件的任何操作,节省开销
答案 6 :(得分:2)
sc.textFile
我只是想知道为什么不wholeTextFiles
例如,在这种情况下......
val minPartitions = 2
val path = "/pathtohdfs"
sc.wholeTextFiles(path,minPartitions)
.flatMap{case (path, text)
...
一个限制是,我们必须加载小文件,否则性能会很差并且可能导致OOM。
注意:
进一步参考visit
答案 7 :(得分:1)
有一种直接的清洁解决方案。使用wholeTextFiles()方法。这将获取一个目录并形成一个键值对。返回的RDD将是一对RDD。 在Spark docs:
下面找到说明SparkContext.wholeTextFiles允许您读取包含多个小文本文件的目录,并将每个文件作为(文件名,内容)对返回。这与textFile形成对比,textFile将在每个文件中每行返回一条记录
答案 8 :(得分:0)
尝试 用于将DataFrame写入外部存储系统(例如文件系统,键值存储等)的接口。使用DataFrame.write()来访问它。
1.4版的新功能。
csv(path,mode = None,compression = None,sep = None,quote = None,escape = None,header = None,nullValue = None,escapeQuotes = None,quoteAll = None,dateFormat = None,timestampFormat = None ) 在指定路径下以CSV格式保存DataFrame的内容。
参数: path –任何Hadoop支持的文件系统中的路径 模式– 指定当数据已经存在时保存操作的行为。
追加:将此DataFrame的内容追加到现有数据。 覆盖:覆盖现有数据。 忽略:如果数据已经存在,则静默忽略此操作。 错误(默认情况):如果数据已经存在,则引发异常。 压缩–保存到文件时使用的压缩编解码器。这可以是已知的不区分大小写的缩写名称(none,bzip2,gzip,lz4,snappy和deflate)。 sep –将单个字符设置为每个字段和值的分隔符。如果设置为None,则使用默认值.。 quote –设置用于转义带引号的值的单个字符,其中分隔符可以是值的一部分。如果设置为None,则使用默认值“。如果要关闭引号,则需要设置一个空字符串。 转义-设置用于在已加引号的值内转义引号的单个字符。如果设置为None,则使用默认值\ escapeQuotes –一个标志,指示是否应始终将包含引号的值括在引号中。如果设置为None,它将使用默认值true,转义包含引号字符的所有值。 quoteAll –一个标志,指示是否应始终将所有值括在引号中。如果设置为None,它将使用默认值false,仅转义包含引号字符的值。 标头–将列名写为第一行。如果设置为None,则使用默认值false。 nullValue –设置空值的字符串表示形式。如果设置为None,它将使用默认值空字符串。 dateFormat –设置指示日期格式的字符串。自定义日期格式遵循java.text.SimpleDateFormat的格式。这适用于日期类型。如果设置为None,则使用默认值yyyy-MM-dd。 timestampFormat –设置指示时间戳格式的字符串。自定义日期格式遵循java.text.SimpleDateFormat的格式。这适用于时间戳类型。如果设置为None,它将使用默认值yyyy-MM-dd'T'HH:mm:ss.SSSZZ。
答案 9 :(得分:-3)
rdd = textFile('/data/{1.txt,2.txt}')