保存到镶木地板子分区

Saving to parquet subpartition

我有一个基于两个分区的目录结构,如下所示:

  People
  > surname=Doe
        > name=John
        > name=Joe
  > surname=White
        > name=Josh
        > name=Julien

我正在阅读仅包含所有 Does 信息的镶木地板文件,因此我直接 指定 surname=Doe 作为我的 DataFrame 的输出目录。现在的问题是我正在尝试在写作时使用 partitionBy("name") 添加基于名称的分区。

df.write.partitionBy("name").parquet(outputDir)

(outputDir 包含 Doe 目录的路径)

这会导致如下错误:

  Caused by: java.lang.AssertionError: assertion failed: Conflicting partition column names detected:
    Partition column name list #0: surname, name
    Partition column name list #1: surname

有什么解决方法吗?这可能是因为在姓氏目录中创建了 _SUCCESS 文件,这给 Spark 提供了错误的提示 - 当我删除 _SUCCESS_metadata 文件时,Spark 能够毫无问题地读取所有内容。

我已经设法通过变通方法解决了它 - 我认为这不是一个好主意,但我禁用了创建额外的 _SUCCESS 和 _metadata 文件:

sc.hadoopConfiguration.set("mapreduce.fileoutputcommitter.marksuccessfuljobs", "false")
sc.hadoopConfiguration.set("parquet.enable.summary-metadata", "false")

这样 Spark 就不会对分区结构有任何愚蠢的想法。

另一个选项是保存到 "proper" 目录 - 人物和按姓氏和名字分区,但是你必须记住,唯一合理的选项是将 SaveMode 设置为 Append 并手动删除您希望被覆盖的目录(这 确实 容易出错):

df.write.mode(SaveMode.Append).partitionBy("surname","name").parquet("/People")

在这种情况下不要使用 owerwrite SaveMode - 这将删除所有姓氏目录。

sc.hadoopConfiguration.set("parquet.enable.summary-metadata", "false")

这是相当明智的,如果您启用了摘要元数据,那么写入元数据文件可能会成为读写的 IO 瓶颈。

您的解决方案的替代方法可能是将 .mode("append") 添加到您的写入中,但将原始父目录作为目标,

df.write.mode("append").partitionBy("name").parquet("/People")