Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 为什么dataset.count会导致洗牌!(火花2.2)_Scala_Apache Spark_Spark Dataframe_Rdd - Fatal编程技术网

Scala 为什么dataset.count会导致洗牌!(火花2.2)

Scala 为什么dataset.count会导致洗牌!(火花2.2),scala,apache-spark,spark-dataframe,rdd,Scala,Apache Spark,Spark Dataframe,Rdd,这是我的数据框: 底层RDD有2个分区 当我进行df.count时,生成的DAG是 当我进行df.rdd.count时,生成的DAG为: Ques:Count是spark中的一个操作,官方定义是“返回数据帧中的行数”。现在,当我在数据帧上执行计数时,为什么会发生洗牌?此外,当我在底层RDD上执行相同的操作时,不会发生洗牌 我不明白为什么会发生洗牌。我试图在这里通读count的源代码,但我完全不明白。提供给该行动的“groupby”是罪魁祸首吗 聚合(1)。计数不会导致任何洗牌 当spa

这是我的数据框:

底层RDD有2个分区

当我进行df.count时,生成的DAG是

当我进行df.rdd.count时,生成的DAG为:

Ques:Count是spark中的一个操作,官方定义是“返回数据帧中的行数”。现在,当我在数据帧上执行计数时,为什么会发生洗牌?此外,当我在底层RDD上执行相同的操作时,不会发生洗牌

我不明白为什么会发生洗牌。我试图在这里通读count的源代码,但我完全不明白。提供给该行动的“groupby”是罪魁祸首吗

聚合(1)。计数不会导致任何洗牌


当spark进行数据帧操作时,它首先计算每个分区的部分计数,然后再进行另一个阶段将这些计数相加。这对于大型数据帧尤其有用,因为将计数分配给多个执行器实际上会提高性能

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

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

看起来DataFrame的计数操作使用了groupBy,从而产生了洗牌。下面是源代码

而如果您查看RDD的count函数,它会将聚合函数传递给每个分区,该函数将每个分区的和作为数组返回,然后使用.sum对数组的元素求和

此链接中的代码段:


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


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

这是有道理的。那么在rdd.count的情况下会发生什么呢?假设rdd有2个分区。这些rdd分区很可能在操作时位于同一执行器上。我不知道关于RDD的更深入的细节,尽管我一直在深入研究DFs的机制。RDD的一个实际用途是,只有在需要转换数据帧或从非结构化源创建数据帧时才使用RDD。由于数据帧处理结构化数据通常更快。我在3个分区的df上运行了测试,并确认您的结果,即单个分区计数是在一个阶段中计算的,然后发生了写入3个分区的随机洗牌。下一阶段将读取这3个分区并将其汇总。然而,这也没有什么意义:为什么要进行洗牌,因为它看起来像一个狭隘的依赖关系转换+操作。我还没有以某种方式验证它(可能访问代码)然而,我相信rdd.count的工作方式是计算各个分区的计数,并将其发送给驱动程序进行最终求和-所有这些都在一个阶段中完成。谢谢Pratyush。几个问题:1。“groupBy().count().queryExecution”到底是如何工作的?既然groupby和count都是方法?2.sc.runJob(this,Utils.getIteratorSize)中的下划线是什么意思?那么,Spark是否保留分区中原始记录的计数?
* 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)
}
/**
* Return the number of elements in the RDD.
*/
def count(): Long = sc.runJob(this, Utils.getIteratorSize _).sum