我有一系列非常大的每日gzip压缩文件。我试图使用PySpark以Parquet格式重新保存S3中的所有文件以备日后使用。
如果是单个文件(例如2012-06-01),我会这样做:
dataframe = spark.read.csv('s3://mybucket/input/20120601.gz', schema=my_schema, header=True)
dataframe.write.parquet('s3://mybucket/output/20120601')
它有效,但由于gzip不可拆分,因此它可以在一台主机上运行,而且我没有使用该集群的好处。
我尝试一次读取一大块文件,并使用partitionBy将输出写入这样的日常文件(例如,在一个月内阅读):
dataframe = spark.read.csv('s3://mybucket/input/201206*.gz', schema=my_schema, header=True)
dataframe.write.partitionBy('dayColumn').parquet('s3://mybucket/output/')
这一次,各个文件在我想要的不同执行程序中读取,但执行程序稍后会死,并且进程失败。我相信因为文件太大了,而且partitionBy在某种程度上使用了不必要的资源(一个随机播放?)它会导致任务崩溃。
我实际上并不需要对数据帧进行重新分区,因为这只是一个1:1的映射。无论如何,是否要将每个单独的任务写入一个单独的,明确命名的镶木地板输出文件?
我在想像
这样的东西def write_file(date):
# get input/output locations from date
dataframe = spark.read.csv(input_location, schema=my_schema, header=True)
dataframe.write.parquet(output_location)
spark.sparkContext.parallelize(my_dates).for_each(write_file)
除非这样做不起作用,因为您无法将火花会话广播到群集。有什么建议吗?
答案 0 :(得分:1)
将输入文件写入单独的输出文件而不重新分区
TL; DR 这是您的代码已经在做的事情。
partitionBy导致不必要的随机播放
没有。 DataFrameWriter.partitionBy
根本没有洗牌。
它有效,但因为gzip不可拆分
你可以:
bzip2
这样的可分割压缩。如果您担心partitionBy
使用的资源(它可能会为每个执行程序线程打开更多文件),您实际上可以随机播放以提高性能 - DataFrame partitionBy to a single Parquet file (per partition)。单个文件可能很多,但
dataframe \
.repartition(n, 'dayColumn', 'someOtherColumn') \
.write.partitionBy('dayColumn') \
.save(...)
可以选择someOtherColumn
来获得合理的基数,应该改进。