Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从S3并行读取多个文件(Spark、Java)_Java_Apache Spark_Amazon S3 - Fatal编程技术网

从S3并行读取多个文件(Spark、Java)

从S3并行读取多个文件(Spark、Java),java,apache-spark,amazon-s3,Java,Apache Spark,Amazon S3,我看到了一些关于这方面的讨论,但不能完全理解正确的解决方案: 我想把几百个文件从S3加载到RDD中。我现在是这样做的: ObjectListing objectListing = s3.listObjects(new ListObjectsRequest(). withBucketName(...). withPrefix(...)); List<String> keys = new LinkedList<>

我看到了一些关于这方面的讨论,但不能完全理解正确的解决方案: 我想把几百个文件从S3加载到RDD中。我现在是这样做的:

ObjectListing objectListing = s3.listObjects(new ListObjectsRequest().
                withBucketName(...).
                withPrefix(...));
List<String> keys = new LinkedList<>();
objectListing.getObjectSummaries().forEach(summery -> keys.add(summery.getKey())); // repeat while objectListing.isTruncated()

JavaRDD<String> events = sc.parallelize(keys).flatMap(new ReadFromS3Function(clusterProps));

我从Scala中看到的同一个问题的答案中“翻译”了这一点。我认为也可以将整个路径列表传递到
sc.textFile(…)
,但我不确定哪种是最佳做法。

您可以使用
sc.textFile
读取多个文件

您可以将
多个文件url
作为其参数传递

您可以指定整个
目录
,使用
通配符
甚至CSV目录和通配符

Ex:

sc.textFile("/my/dir1,/my/paths/part-00[0-5]*,/another/dir,/a/specific/file")

潜在的问题是,在s3中列出对象的速度非常慢,而且每当有东西执行树遍历时,它看起来像目录树的方式会降低性能(就像路径的通配符模式加工一样)

这篇文章中的代码列出了所有的子类,它提供了更好的性能,这基本上是Hadoop 2.8和s3a listFiles(path,recursive)附带的

在获得该列表后,您将得到指向对象路径的字符串,然后可以将其映射到s3a/s3n路径,以便spark将其作为文本文件输入处理,然后可以对其应用工作

val files = keys.map(key -> s"s3a://$bucket/$key").mkString(",")
sc.textFile(files).map(...)
根据要求,这里是使用的java代码

String prefix = "s3a://" + properties.get("s3.source.bucket") + "/";
objectListing.getObjectSummaries().forEach(summary -> keys.add(prefix+summary.getKey())); 
// repeat while objectListing truncated 
JavaRDD<String> events = sc.textFile(String.join(",", keys))
String prefix=“s3a://”+properties.get(“s3.source.bucket”)+“/”;
objectListing.getObjectSummaries().forEach(summary->keys.add(prefix+summary.getKey());
//在对象列表被截断时重复
javarddevents=sc.textFile(String.join(“,”键))

请注意,我将s3n切换为s3a,因为如果您的CP上有
hadoop aws
amazon sdk
JAR,那么您应该使用s3a连接器。它更好,而且它是由人(我)根据spark工作负载进行维护和测试的。请参阅。

我想,如果您在阅读aws时尝试并行化,将利用executor,并肯定会提高性能

val bucketName=xxx
val keyname=xxx
val df=sc.parallelize(new AmazonS3Client(new BasicAWSCredentials("awsccessKeyId", "SecretKey")).listObjects(request).getObjectSummaries.map(_.getKey).toList)
        .flatMap { key => Source.fromInputStream(s3.getObject(bucketName, keyname).getObjectContent: InputStream).getLines }

使用通配符的问题是,它会导致对list()的多次调用,这会导致spark作业长时间没有响应。这就是为什么建议首先获取所有密钥,然后并行化它们。请参见此处:感谢Steve的回答,我正尝试在AWS EMR上使用这两个选项运行代码(使用我的自定义映射函数并将所有路径传递到
textFile(…)
但是我在让它正常运行时遇到了一些问题。一旦我成功运行它并比较性能,我将更新此线程。很好!我用7个1GB文件进行了尝试,使用
textFile(…)
(比我的自定义代码快50%)。那么,您能否用相应的Java代码更新您的回复,我将接受它?
String prefix=“s3n://”+properties.get(“s3.source.bucket”)+“/”objectListing.getObjectSummaries().forEach(summery->keys.add(prefix+summery.getKey());//在截断时重复
尝试使用s3a,对我来说很好。需要
包com.amazonaws:aws java sdk pom:1.10.34,org.apache.hadoop:hadoop aws:2.7.2
作为参数来spark submit,我认为也需要
sc.hadoopConfiguration().set(“fs.s3.impl”,“org.apache.hadoop.fs.s3a.s3a.S3AFileSystem”)
在代码中。EMR应该具有IAM角色,具有从存储桶读/写的权限。这样,您就可以执行
AmazonS3 s3=new AmazonS3Client()
和cred将被自动拾取。如果有大量的键,这将不起作用,比如说亿万富翁。这看起来不错。listObjects通常会成批返回结果,所以我假设会有一个循环。是的,这段代码需要更多的逻辑来处理被截断的列表。
val bucketName=xxx
val keyname=xxx
val df=sc.parallelize(new AmazonS3Client(new BasicAWSCredentials("awsccessKeyId", "SecretKey")).listObjects(request).getObjectSummaries.map(_.getKey).toList)
        .flatMap { key => Source.fromInputStream(s3.getObject(bucketName, keyname).getObjectContent: InputStream).getLines }