【发布时间】:2016-08-26 08:55:33
【问题描述】:
我有两个大的 csv 文件,由其中一列预先排序。有没有办法利用它们已经排序的事实更快地获得新的排序 RDD,而无需再次完全排序?
【问题讨论】:
标签: sorting apache-spark rdd
我有两个大的 csv 文件,由其中一列预先排序。有没有办法利用它们已经排序的事实更快地获得新的排序 RDD,而无需再次完全排序?
【问题讨论】:
标签: sorting apache-spark rdd
简短的回答:不,当使用 Apache Spark 提供的排序工具时,没有办法利用两个输入 RDD 已经排序的事实。
长答案:在某些情况下,可能有比使用sortBy 或sortByKey 更好的方法。
最明显的情况是输入 RDD 已经排序并表示不同的范围。在这种情况下,简单地使用 rdd1.union(rdd2) 是组合输入 RDD 的最快(几乎为零成本)方式,假设 rdd1 中的所有元素都在 rdd2 中的所有元素之前(根据选择的顺序)。
当输入 RDD 的范围重叠时,事情变得更加棘手。假设目标 RDD 应该只有一个分区,在两个 RDD 上使用toLocalIterator 然后手动进行合并可能是有效的。如果结果必须是 RDD,可以在自定义 RDD 类型的 compute 方法中执行此操作,处理输入 RDD 并生成输出。
当输入很大并因此包含许多分区时,事情变得更加棘手。在这种情况下,您可能还希望输出 RDD 中有多个分区。您可以使用前面提到的自定义 RDD,但创建多个分区(使用 RangePartitioner)。每个分区将覆盖不同范围的元素(在最佳情况下,这些范围将覆盖大致相同大小的输出部分)。
其中的棘手部分是避免在compute 内多次处理完整的输入 RDD。当输入 RDD 使用RangePartitioner 时,可以使用OrderedRDDFunctions 中的filterByRange 有效地避免这种情况。当他们不使用RangePartitioner,但您知道分区是内部排序的并且具有全局顺序时,您首先需要通过实际探测数据找出这些分区所覆盖的有效范围。
由于多分区情况相当复杂,我会检查自定义排序是否真的比简单地使用sortBy或sortByKey更快。 sortBy 和 sortByKey 的逻辑针对洗牌过程(在节点之间传输数据)进行了高度优化。出于这个原因,很可能在许多情况下,这些方法比定制逻辑更快,即使定制逻辑可能是 O(n) 而 sortBy / sortByKey 可能是 O(n log (n)) 充其量。
如果您有兴趣了解更多关于 Apache Spark 使用的洗牌逻辑,有一个 article 解释基本概念。
【讨论】: