将文件保存到 Parquet 时,分区列移动到行尾

jav*_*dba 5 apache-spark parquet

对于一个给定的 DataFrame 就在被save送到parquet这里之前是架构:注意centroid0第一列并且是StringType

在此处输入图片说明

但是,当使用以下方法保存文件时:

      df.write.partitionBy(dfHolder.metadata.partitionCols: _*).format("parquet").mode("overwrite").save(fpath)
Run Code Online (Sandbox Code Playgroud)

并使用partitionColsas centroid0

在此处输入图片说明

然后有一个(对我来说)令人惊讶的结果:

  • centroid0分配柱已被移动到所述端部的行的
  • 数据类型已更改为 Integer

我通过println以下方式确认了输出路径:

 path=/git/block/target/scala-2.11/test-classes/data/output/blocking/out//level1/clusters
Run Code Online (Sandbox Code Playgroud)

这是从保存的读回时的模式parquet

在此处输入图片说明

为什么会发生对输入模式的这两个修改 - 以及如何避免它们 - 同时仍将 保持centroid0为分区列?

更新 首选答案应该提到为什么/何时将分区添加到列列表的末尾(与开头)。我们需要了解确定性排序。

另外 - 有没有办法让spark推断的列类型“改变主意”?我不得不改变从分区01等来c0c1等为了得到推理来映射StringType。也许这是必需的..但是如果有一些火花设置来改变行为,这将是一个很好的答案。

Arn*_*-Oz 4

当你write.partitionBy(...)Spark 将分区字段保存为文件夹时,这对于稍后读取数据是有益的,因为(对于某些文件类型,包括镶木地板)它可以优化仅从您使用的分区读取数据(即,如果您'd 读取并过滤 centroid0==1 Spark 不会读取其他分区

这样做的效果是分区字段(centroid0在您的情况下)不会仅作为文件夹名称(centroid0=1centroid0=2

这些的副作用是 1. 分区的类型是在运行时推断的(因为架构没有保存在镶木地板中),并且在您的情况下,碰巧您只有整数值,因此它被推断为整数。

另一个副作用是分区字段被添加到模式的末尾/开头,因为它从镶木地板文件中读取模式作为一个块,然后将分区字段作为另一个块添加到该分区字段(同样,它是不再是存储在 parquet 中的架构的一部分)