如何在S3上合并多个Parquet文件?(不重分区Spark DataFrame)
直接在S3上合并Parquet文件的几种方案
当然有办法!不用把文件拉到本地折腾,直接在云端就能搞定,给你几个实用的方案,适配不同的场景:
方案1:用Spark快速合并(最推荐)
既然你本身就熟悉Spark,这是最直接的方式——读取S3上的多份Parquet文件,合并成单个分区后再写回S3。关键是用coalesce(1)而不是repartition(1),前者不会触发shuffle,性能要好得多,完全符合你不想无谓消耗资源的需求。
代码示例
Scala版本
spark.read.parquet("s3://your-source-bucket/path-to-multiple-parquets/") .coalesce(1) // 合并到1个分区,无shuffle .write.mode("overwrite") // 按需选择模式:append/overwrite等 .parquet("s3://your-target-bucket/path-to-single-parquet/")
Python版本
spark.read.parquet("s3://your-source-bucket/path-to-multiple-parquets/") \ .coalesce(1) \ .write.mode("overwrite") \ .parquet("s3://your-target-bucket/path-to-single-parquet/")
执行后,目标路径下会生成一个part-*.parquet文件,就是合并后的单个文件了。Spark会直接在S3上完成读写,全程不需要本地中转。
方案2:用AWS Athena(适合已有Athena表的场景)
如果你的Parquet文件已经在Athena中注册成了表,可以用CTAS(Create Table As Select)语句直接生成单个Parquet文件到S3。不过要注意:Athena默认会根据数据量分文件,想要强制单个文件的话,需要确保查询结果的数据量不大,或者通过调整参数限制输出文件数。
SQL示例
CREATE TABLE single_parquet_output WITH ( format = 'PARQUET', external_location = 's3://your-target-bucket/single-file-path/', write_compression = 'SNAPPY' -- 可选,压缩格式 ) AS SELECT * FROM "your_database"."your_parquet_table"
执行后,目标S3路径下会生成合并后的Parquet文件。如果数据量较大,可能还是会生成多个文件,这时候可以结合LIMIT或者先聚合,但如果你的数据量本来就适合单文件存储,这个方法很省心。
注意事项
- 合并成单个文件虽然满足了需求,但后续读取时无法并行加载,大文件会影响读取性能,需要根据你的实际使用场景权衡。
- 如果用Spark方案,确保你的Spark集群有足够的内存处理整个数据集(因为coalesce(1)会把所有数据放到一个 executor 里)。
内容的提问来源于stack exchange,提问作者Akarsh Gupta
相关产品推荐
相关产品推荐

