PySpark覆盖指定Parquet文件且不影响其他文件的实现方法
PySpark 仅覆盖目标Parquet文件、保留同目录其他文件的实现方法
针对分区写入时默认overwrite模式会清空上层分区目录、误删其他无关文件的问题,可根据写入场景选择以下两种方案:
方案1:动态分区覆盖(推荐,适配常规分区写入场景)
Spark 2.3及以上版本提供了动态分区覆盖配置,开启后写入时只会覆盖本次数据实际命中的分区目录,完全不会触碰其他无关分区的文件,正好匹配三级分区目录的使用场景。
写入前先设置配置参数即可:
# 开启动态分区覆盖模式 spark.conf.set("spark.sql.sources.partitionOverwriteMode", "dynamic") # 按年/月/日分区写入根路径,假设当前df仅包含2021年12月1日的数据 df.write.mode("overwrite") \ .partitionBy("year", "month", "day") \ .parquet("root/")
- 效果:写入时只会清空
root/2021/12/01/目录下的旧文件再写入新内容,root/2021/12/02/、root/2021/12/03/下的文件完全不受影响。
方案2:精确删除目标文件后追加写入(适配固定单文件路径写入场景)
如果不需要走Spark的自动分区发现逻辑,就是要写入某个固定的精确文件路径,可以先通过Hadoop API仅删除目标路径本身,再用append模式写入,不会波及上层目录的其他文件:
# 导入Java侧依赖,操作Hadoop文件系统 from py4j.java_gateway import java_import java_import(spark._jvm, 'org.apache.hadoop.fs.Path') target_file_path = "root/2021/12/01/file1.parquet" hadoop_conf = spark._jsc.hadoopConfiguration() target_path = spark._jvm.Path(target_file_path) fs = target_path.getFileSystem(hadoop_conf) # 仅当目标文件存在时,删除该文件本身,不会递归删除上层目录内容 if fs.exists(target_path): fs.delete(target_path, True) # 合并为1个文件输出,匹配单文件命名需求,不需要单文件可删除coalesce(1) df.coalesce(1).write.mode("append").parquet(target_file_path)
避坑说明
- 不要直接使用默认配置下的
mode("overwrite")写入分区根路径,默认spark.sql.sources.partitionOverwriteMode=STATIC,Spark会清空写入路径下的所有子目录内容,直接删除其他分区的所有文件,这也是默认模式下出现无关文件被覆盖的原因。 - 手动删除文件时务必核对路径,不要传入上层目录路径,否则会误删整个目录下的所有内容。
内容的提问来源于stack exchange,提问作者bda
相关产品推荐
相关产品推荐

