在将RDD写入文件之前执行以下转换时有什么区别?
代码示例:
val input = sc.textFile(inputFile)
val filtered = input.filter(doSomeFiltering)
val mapped = filtered.map(doSomeMapping)
mapped.coalesce(1, shuffle = true).saveAsTextFile(outputFile)
vs
mapped.coalesce(1, shuffle = false).saveAsTextFile(outputFile)
它与collect()相比如何?我完全知道Spark保存方法会将它存储为HDFS风格的结构,但是我对collect()和shuffled / non-shuffled coalesce()的数据分区方面更感兴趣。
答案 0 :(得分:5)
shuffle = true和shuffle = false不会在结果输出中产生任何实际差异,因为它们都会下降到单个分区。但是,当你将它设置为true时,你将进行一次没有任何用途的随机播放。使用shuffle = true,输出均匀分布在分区之间(如果需要,还可以增加分区数),但由于目标是1分区,所以一切都在一个分区中结束。
至于与collect()的比较,区别在于所有数据都存储在单个执行器而不是驱动程序上。
答案 1 :(得分:3)
通过查看Spark 2.3.1的合并文档, https://spark.apache.org/docs/2.3.1/api/java/org/apache/spark/rdd/RDD.html#coalesce-int-boolean-scala.Option-scala.math.Ordering-
当您将分区数减少到1时,添加shuffle = true看起来更方便,以避免在比您希望的节点数更少的节点上进行计算。这将增加一个随机播放步骤,但意味着当前的上游分区将并行执行。
答案 2 :(得分:0)
coalesce(n, shuffle = true)
也等同于retartition(n)
,具体取决于您父RDD中的映射或其他任何处理登录名,这对您的< em> job 执行。
通常,当父分区中的数据均匀分布并且您的分区数量并未急剧减少时,使用coalesce
时应避免使用 shuffle 。
但是,在您的情况下,分区数量大大减少了,并且按照documentation
但是,如果您要进行剧烈的合并,例如到numPartitions = 1, 这可能导致您的计算发生在少于 您喜欢(例如,在numPartitions = 1的情况下为一个节点)。为了避免这种情况, 您可以传递shuffle = true。这将增加一个随机播放步骤,但意味着 当前的上游分区将并行执行(无论 当前分区是)
鉴于此,现在您需要正确评估并在
之间进行选择例如,考虑以下片段,这些片段与您可能拥有的实际逻辑相去甚远,但可以使您对正在发生的事情有个看法
sc.parallelize(0 to 1000000, 10)
.mapPartitions(it => {Thread.sleep(5000); it.map(_.toString)})
.coalesce(1, shuffle = true)
.toDF.write.text("shuffleTrue")
sc.parallelize(0 to 1000000, 10)
.mapPartitions(it => {Thread.sleep(5000); it.map(_.toString)})
.coalesce(1, shuffle = false)
.toDF.write.text("shuffleFalse")
在我的群集中,shuffle = true
总共显示了大约10分钟的 5秒时间,并在每个父分区上并行执行计算逻辑。
而另一个拥有shuffle = true
的人大约用 50秒在一个执行器上完成单个任务内的所有计算。