Apache Spark中的混乱与非混乱合并

时间:2015-06-17 18:37:11

标签: scala apache-spark bigdata distributed-computing

在将RDD写入文件之前执行以下转换时有什么区别?

  1. coalesce(1,shuffle = true)
  2. coalesce(1,shuffle = false)
  3. 代码示例:

    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()的数据分区方面更感兴趣。

3 个答案:

答案 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秒在一个执行器上完成单个任务内的所有计算