为什么dataset.count导致shuffle! (火花2.2)

时间:2017-11-09 04:54:53

标签: scala apache-spark spark-dataframe rdd

这是我的数据框:

enter image description here

底层RDD有2个分区

enter image description here enter image description here

当我执行df.count时,生成的DAG是 enter image description here

当我执行df.rdd.count时,生成的DAG是:

enter image description here

问题:Count是spark中的一个动作,官方定义是'返回DataFrame中的行数'。现在,当我对数据帧执行计数时,为什么会发生洗牌?此外,当我在底层RDD上做同样的事情时,不会发生随机播放。

对我来说无论如何都会发生洗牌是没有意义的。我试图在这里查看计数的源代码spark github但这对我来说没有任何意义。 “groupby”是否被提供给行动罪魁祸首?

  

PS。 df.coalesce(1).count不会导致任何随机播放

3 个答案:

答案 0 :(得分:4)

似乎DataFrame的count计数操作使用groupBy导致shuffle。以下是https://github.com/apache/spark/blob/master/sql/core/src/main/scala/org/apache/spark/sql/Dataset.scala

的代码
* Returns the number of rows in the Dataset.
* @group action
* @since 1.6.0
*/
def count(): Long = withAction("count", groupBy().count().queryExecution) { 
plan =>
plan.executeCollect().head.getLong(0)
}

如果你看一下RDD的count函数,它会将聚合函数传递给每个分区,它们将每个分区的总和作为Array返回,然后使用.sum对数组的元素求和。

此链接的代码段: https://github.com/apache/spark/blob/master/core/src/main/scala/org/apache/spark/rdd/RDD.scala

/**
* Return the number of elements in the RDD.
*/
def count(): Long = sc.runJob(this, Utils.getIteratorSize _).sum

答案 1 :(得分:3)

当spark正在进行数据帧操作时,它首先计算每个分区的部分计数,然后使用另一个阶段将它们加在一起。这对于大型数据帧尤其有用,其中向多个执行程序分配计数实际上增加了性能。

验证这一点的地方是Spark UI的 SQL 选项卡,它将具有以下物理计划描述:

*HashAggregate(keys=[], functions=[count(1)], output=[count#202L])
+- Exchange SinglePartition
   +- *HashAggregate(keys=[], functions=[partial_count(1)], output=[count#206L])

答案 2 :(得分:1)

在洗牌阶段,键为空,值是分区的计数,所有这些(键,值)对都被洗牌到一个分区中。

也就是说,在洗牌阶段移动的数据很少。