将Spark数据帧作为镶木地板写入S3而不创建_temporary文件夹

时间:2017-09-28 08:08:08

标签: hadoop apache-spark amazon-s3 pyspark

使用pyspark我正在从Amazon S3上的镶木地板文件中读取数据框,如

dataS3 = sql.read.parquet("s3a://" + s3_bucket_in)

这没有问题。但后来我尝试写数据

dataS3.write.parquet("s3a://" + s3_bucket_out)

我确实得到以下异常

py4j.protocol.Py4JJavaError: An error occurred while calling o39.parquet.
: java.lang.IllegalArgumentException: java.net.URISyntaxException: 
Relative path in absolute URI: s3a://<s3_bucket_out>_temporary

在我看来,Spark在写入写入给定存储桶之前首先尝试创建_temporary文件夹。这可以以某种方式防止,因此spark直接写入给定的输出桶吗?

2 个答案:

答案 0 :(得分:5)

您无法删除_temporary文件,因为它用于保存中间文件 隐藏查询的工作直到完成

但是没关系,因为这不是问题所在。问题是输出提交者在尝试写入根目录时有点困惑(不能删除它,请参阅)

您需要使用完整前缀写入存储桶下的子目录。例如 s3a://mybucket/work/out

我应该补充一点,尝试将数据提交到S3A是不可靠的,正是因为它模仿rename()类似于ls -rlf src | xargs -p8 -I% "cp % dst/% && rm %"的方式。由于ls在S3上延迟了一致性,因此可能会错过新创建的文件,因此不要复制它们。

有关详细信息,请参阅:Improving Apache Spark

现在,您只能通过写入HDFS然后复制来可靠地提交到s3a。 EMR s3通过使用DynamoDB提供一致的列表

来解决这个问题

答案 1 :(得分:2)

在编写S3存储桶的根目录时遇到了同样的问题:

df.save("s3://bucketname")

我通过在存储桶名称后面添加/解决了这个问题:

df.save("s3://bucketname/")