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

时间:2018-06-21 07:38:14

标签: apache-spark parquet

对于save即将到parquet之前的给定DataFrame,以下是架构:请注意,centroid0 first 列,并且是{ {1}}:

enter image description here

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

StringType

,其中 df.write.partitionBy(dfHolder.metadata.partitionCols: _*).format("parquet").mode("overwrite").save(fpath) partitionCols

enter image description here

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

  • centroid0分区列已移至行的 end
  • 数据类型已更改为centroid0

我通过Integer确认了输出路径:

println

这是从保存的 path=/git/block/target/scala-2.11/test-classes/data/output/blocking/out//level1/clusters 读取 back 时的架构:

enter image description here

为什么对输入模式进行了这两种修改-以及如何避免它们-仍将parquet保留为分区列?

更新一个优选的答案应该是为什么/当将分区添加到列列表的 end (相对于开始)时。我们需要对确定性排序的理解。

此外-是否有任何方法可以使centroid0对推断出的列类型“改变主意”?我不得不将分区从spark0等更改为1c0等,以便将推断映射到c1。也许这是必需的..但是如果有一些火花设置可以改变行为,那么这将是一个很好的答案。

2 个答案:

答案 0 :(得分:1)

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

此操作的结果是,分区字段(在您的情况下为centroid0)不会仅作为文件夹名称(centroid0=1centroid0=2等)写入实木复合地板文件中< / p>

这些的副作用是1.在运行时推断分区的类型(因为架构未保存在Parquet中),在您的情况下,您碰巧只有整数值,因此推断为整数

另一个副作用是,分区字段是在模式的末尾/开头添加的,因为它从拼花文件中读取模式是一个块,然后又将分区字段添加为另一个(再次) ,它不再是存储在实木复合地板中的架构的一部分)

答案 1 :(得分:0)

原因实际上很简单。当按一列进行分区时,每个分区只能包含所述列的一个值。因此,实际上在文件的各处都写入相同的值是没有用的,这就是Spark不这样做的原因。读取文件时,Spark使用文件名中包含的信息来重建分区列,并将其放在模式的末尾。列的类型不会存储,而是在读取时进行推断,因此您需要使用整数类型。 注意:关于在末尾添加该列的原因没有特别的原因。可能只是开始。我想这只是实现的任意选择。

为避免丢失列的类型和顺序,可以像df.withColumn("X", 'YOUR_COLUMN).write.partitionBy("X").parquet("...")这样复制分区列。

但是,您将浪费空间。另外,例如,spark使用分区来优化过滤器。读取数据后,请不要忘记使用X列作为过滤器,否则您的列或Spark将无法执行任何优化。