这是我的数据框:
底层RDD有2个分区
当我执行df.rdd.count时,生成的DAG是:
问题:Count是spark中的一个动作,官方定义是'返回DataFrame中的行数'。现在,当我对数据帧执行计数时,为什么会发生洗牌?此外,当我在底层RDD上做同样的事情时,不会发生随机播放。
对我来说无论如何都会发生洗牌是没有意义的。我试图在这里查看计数的源代码spark github但这对我来说没有任何意义。 “groupby”是否被提供给行动罪魁祸首?
PS。 df.coalesce(1).count不会导致任何随机播放
答案 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)
在洗牌阶段,键为空,值是分区的计数,所有这些(键,值)对都被洗牌到一个分区中。
也就是说,在洗牌阶段移动的数据很少。