我可以从S3读取多个文件到Spark Dataframe中,传递不存在的文件吗?

时间:2017-01-18 01:40:05

标签: python apache-spark pyspark apache-spark-sql pyspark-sql

我想从S3读取多个镶木地板文件到数据框中。目前,我正在使用以下方法执行此操作:

files = ['s3a://dev/2017/01/03/data.parquet',
         's3a://dev/2017/01/02/data.parquet']
df = session.read.parquet(*files)

如果S3上存在所有文件,这是有效的,但我想要一个文件列表加载到数据框中,而不会在列表中的某些文件不存在时中断。换句话说,我希望sparkSql能够在数据帧中加载尽可能多的文件,并在不抱怨的情况下返回此结果。这可能吗?

4 个答案:

答案 0 :(得分:4)

是的,如果您更改指定输入到hadoop glob模式的方法,则可能是这样的,例如:

files = 's3a://dev/2017/01/{02,03}/data.parquet'
df = session.read.parquet(files)

您可以在Hadoop javadoc中了解有关模式的更多信息。

但是,在我看来,这不是处理按时间划分的数据的优雅方式(在你的情况下按天)。如果您能够重命名这样的目录:

  • s3a://dev/2017/01/03/data.parquet - > s3a://dev/day=2017-01-03/data.parquet
  • s3a://dev/2017/01/02/data.parquet - > s3a://dev/day=2017-01-02/data.parquet

然后您可以利用spark partitioning架构并通过以下方式读取数据:

session.read.parquet('s3a://dev/') \
    .where(col('day').between('2017-01-02', '2017-01-03')

这种方式也会省略空/不存在的目录。 Additionall列day将出现在您的数据框中(它将在spark< 2.1.0中的字符串和spark中的日期时间> = 2.1.0),因此您将知道每个记录在哪个目录中存在。

答案 1 :(得分:1)

我可以观察到,由于glob-pattern匹配包括完整的递归树遍历和路径的模式匹配,它是对对象存储的绝对性能杀手,尤其是S3。火花中有一个特殊的快捷方式,用于识别路径中没有任何全局字符,在这种情况下,它会提供更有效的选择。

同样,非常深的分区树,如年/月/日布局,意味着扫描了许多目录,每个目录的成本为数百毫安(或更差)。

Mariusz建议的布局应该更有效率,因为它是一个更平坦的目录树 - 切换它应该对对象存储的性能产生比真实文件系统更大的影响。

答案 2 :(得分:0)

使用union

的解决方案
files = ['s3a://dev/2017/01/03/data.parquet',
         's3a://dev/2017/01/02/data.parquet']

for i, file in enumerate(files):
    act_df = spark.read.parquet(file)   
    if i == 0:
        df = act_df
    else:
        df = df.union(act_df)

一个优点是,无论任何模式,都可以完成。

答案 3 :(得分:0)

import sys
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.transforms import *
from awsglue.dynamicframe import DynamicFrame
from awsglue.utils import getResolvedOptions
from awsglue.job import Job

import boto3


sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)


inputDyf = lueContext.create_dynamic_frame.from_options(connection_type="parquet", connection_options={'paths': ["s3://dev-test-laxman-new-bucket/"]})

我能够从 s3://dev-test-laxman-new-bucket/ 读取多个 (2) 镶木地板文件并写入 csv 文件。 enter image description here

如您所见,我的存储桶中有 2 个 parqet 文件:

希望对其他人有所帮助。