RDD中是否有任何操作可以保持订单?

时间:2016-08-05 04:48:35

标签: scala apache-spark rdd reduce fold

我希望RDD性能中的操作与reduce相似,但不需要操作符可交换。即我希望跟随的result始终为"123456789"

scala> val rdd = sc.parallelize(1 to 9 map (_.toString))
rdd: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[24] at parallelize at <console>:24

scala> val result = rdd.someAction{ _+_ }

首先,我找到了foldRDD#fold的文件说:

  

def fold(zeroValue:T)(op:(T,T)⇒T):T聚合元素   每个分区,然后是所有分区的结果,使用a   给定关联函数和中性“零值”

请注意,doc中不需要 可交换 。但是,结果并不像预期的那样:

scala> rdd.fold(""){ _+_ }
res10: String = 312456879

编辑我试过@ dk14提到的,没有运气:

scala> val rdd = sc.parallelize(1 to 9 map (_.toString))
rdd: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[48] at parallelize at <console>:24

scala> rdd.zipWithIndex.map(x => (x._2, x._1)).sortByKey().map(_._2).fold(""){ _+_ }
res22: String = 341276895

scala> rdd.zipWithIndex.map(x => (x._2, x._1)).sortByKey().map(_._2).fold(""){ _+_ }
res23: String = 914856273

scala> rdd.zipWithIndex.map(x => (x._2, x._1)).sortByKey().map(_._2).fold(""){ _+_ }
res24: String = 742539618

scala> rdd.zipWithIndex.map(x => (x._2, x._1)).sortByKey().map(_._2).fold(""){ _+_ }
res25: String = 271468359

2 个答案:

答案 0 :(得分:2)

在Scala中没有满足此条件的内置缩减操作,但您可以通过合并mapPartitionscollect和本地缩减来轻松实现自己的操作:

import scala.reflect.ClassTag

def orderedFold[T : ClassTag](rdd: RDD[T])(zero: T)(f: (T, T) => T): T = {
  rdd.mapPartitions(iter => Iterator(iter.foldLeft(zero)(f))).collect.reduce(f)
}

使用collectreduce的组合代替fold使用的异步和无序方法,可确保保留全局顺序。

这当然会带来一些额外费用,包括:

  • 驱动程序的内存占用量略高。
  • 显着更高的延迟 - 我们在开始本地缩减之前明确等待所有任务完成。

答案 1 :(得分:1)

正如@YuvalItzchakov所指出的fold在合并结果时不会保留分区RDD中的排序。为了说明这一点,请考虑将原始RDD合并到一个唯一的分区

scala> val rdd = sc.parallelize(1 to 9 map (_.toString)).coalesce(1)
rdd: org.apache.spark.rdd.RDD[String] = CoalescedRDD[27] at coalesce at <console>:27

scala> rdd.zipWithIndex.map(x => (x._2, x._1)).sortByKey().map(_._2).fold(""){ _+_ }
res4: String = 123456789

scala> rdd.zipWithIndex.map(x => (x._2, x._1)).sortByKey().map(_._2).fold(""){ _+_ }
res5: String = 123456789

scala> rdd.zipWithIndex.map(x => (x._2, x._1)).sortByKey().map(_._2).fold(""){ _+_ }
res6: String = 123456789