在 Spark 中保存有序数据帧

Ale*_*ann 5 hadoop dataframe apache-spark

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

dataFrame.orderBy("index").write().mode(SaveMode.Overwrite).parquet(getPath());
Run Code Online (Sandbox Code Playgroud)

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

在将数据保存到磁盘期间,是否有任何特定的群集设置来保留排序?或者它是spark版本的已知问题?我搜索了 spark 文档,但找不到任何相关信息。

更新:

我检查了镶木地板中的文件,并且在这两种情况下文件都已排序。所以读取时会出现问题,Spark 1.5.0 不会在读取时保留顺序,而 1.6.0 会。

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

Ass*_*son 4

这里发生了几件事:

  1. 当您写入时,spark 将数据拆分为多个分区,并且这些分区是单独写入的,因此即使数据是有序的,它也会被拆分。

  2. 当您读取分区时,不会保存它们之间的顺序,因此您将仅对块进行排序。更糟糕的是,文件到分区的 1:1 映射可能有所不同:

    • 多个文件可能以错误的顺序映射到单个分区,导致分区内的排序仅在块中正确
    • 单个文件可以在分区之间划分(如果它大于块大小)。

基于上述,最简单的解决方案是在写入时重新分区(或者更确切地说合并)为1,从而拥有1个文件。当读取该文件时,如果文件小于块大小,则数据将被排序(您甚至可以使块大小非常大以确保这一点)。

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

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