Azure Databricks:非分区Parquet追加分区DataFrame时原数据被覆盖的原因
在Azure Databricks中,当存储路径下存在未按指定列分区的Parquet文件时,后续使用partitionBy("some_column")以append模式写入新DataFrame,原非分区数据会被覆盖。为什么会出现这种情况?append操作为何不重新分区初始数据,或者给出数据将被覆盖的警告?
示例代码
示例1:最终仅保留df2的数据
# 初始化DataFrame(未分区写入) df1.write.mode("overwrite").parquet(file_path) # 使用partitionBy追加写入 df2.write.mode("append").partitionBy("column1").parquet(file_path)
示例2:最终保留两个DataFrame的数据
# 初始化DataFrame(按column1分区写入) df1.write.mode("overwrite").partitionBy("column1").parquet(file_path) # 使用partitionBy追加写入 df2.write.mode("append").partitionBy("column1").parquet(file_path)
原因说明
存储结构冲突导致的自动清理:第一次写入未分区Parquet时,文件直接存放在根路径(如
file_path/part-xxxx.snappy.parquet);而用partitionBy写入时,Spark会生成分区子目录(如file_path/column1=xxx/part-xxxx.snappy.parquet)。append模式下,Spark会判定根路径下的非分区文件不符合当前分区结构,为了保证数据存储格式的一致性,会自动删除这些非分区文件,只保留分区目录下的数据——这不是传统意义的“覆盖”,而是对不匹配结构数据的清理。append模式的设计边界:append模式的核心是追加新数据,而非修改已有数据的存储结构。它不会自动重分区原有数据,因为这需要全量重写已有数据,性能开销极大,Spark默认不会做这种假设。如果需要合并非分区和分区数据,你得先读取原数据,重新分区后再和新数据合并写入。
无警告的原因:当前Spark(包括Databricks Runtime)将这种场景视为预期行为——当写入格式与目标路径现有文件结构不匹配时,会清理不兼容文件。由于这属于存储结构不匹配的边缘场景,默认没有触发警告的逻辑,需要用户自己保证写入时的结构一致性。
内容的提问来源于stack exchange,提问作者user24932649

