在Spark中保存有序的数据帧

时间:2016-12-28 14:58:39

标签: hadoop apache-spark dataframe

我试图将有序数据帧保存到HDFS中。我的代码如下所示:

dataFrame.orderBy("index").write().mode(SaveMode.Overwrite).parquet(getPath());

我在两个不同的集群上运行相同的代码,一个集群使用Spark 1.5.0,另一个集群使用1.6.0。在使用Spark 1.5.0在群集上运行时,它在保存到光盘后不会保留排序。

在光盘上保存数据时是否有任何特定的群集设置来保留排序?或者它是火花版的已知问题?我搜索过spark文档,但无法找到有关的信息。

更新

我检查了镶木地板中的文件,在这两种情况下都会对文件进行排序。因此在阅读时会出现问题,Spark 1.5.0在读取时不会保留排序,而1.6.0则不会。

现在我的问题是:是否可以在Spark 1.5.0中读取已排序的文件并保留排序?

1 个答案:

答案 0 :(得分:2)

这里有几件事情发生了:

  1. 当你写作时,spark会将数据分成几个分区,并且这些分区是分开编写的,所以即使数据是有序的,它也会被拆分。

  2. 当您阅读分区时,不保存它们之间的顺序,因此您只能对块进行排序。更糟糕的是,可能存在与文件到分区的1:1映射不同的东西:

    • 可能会以错误的顺序将多个文件映射到单个分区,导致分区内的排序仅在块中为true
    • 单个文件可能在分区之间划分(如果它大于块大小)。
  3. 基于以上所述,最简单的解决方案是在写入时重新分区(或者更确切地说是合并)为1,因此有1个文件。当读取该文件时,如果文件小于块大小,则将对数据进行排序(您甚至可以使块大小非常大以确保这一点)。

    此解决方案的问题在于它降低了并行性(当您编写时需要重新分区,当您阅读时,您需要再次重新分区以获得并行性。合并/重新分区可能成本高昂。 这个解决方案的第二个问题是它不能很好地扩展(你最终可能会得到一个巨大的文件)。

    更好的解决方案将基于您的用例。基本是如果您可以在排序之前使用分区。例如,如果您计划执行需要排序的自定义聚合,那么如果确保在文件和分区之间保持1:1映射,则可以确保在分区内进行排序,这可能足够您。您还可以将每个分区中的最大值添加为第二个值,然后将其分组并进行二次排序。