为什么 dataset.count() 比 rdd.count() 更快?

9
我创建了一个 Spark Dataset[Long]
scala> val ds = spark.range(100000000)
ds: org.apache.spark.sql.Dataset[Long] = [id: bigint]

当我运行ds.count时,它在4核8GB的机器上用0.2s返回结果。同时,它创建的DAG如下所示:

enter image description here

但是,当我运行ds.rdd.count时,它在同样的机器上用4s返回结果。但是它创建的DAG如下所示:

enter image description here

所以,我的疑问是:
  1. 为什么ds.rdd.count只创建一个stage,而ds.count创建了2个stage?
  2. 此外,当ds.rdd.count只有一个stage时,为什么比有2个stage的ds.count更慢?

1
据我所知,ds.rdd.count非常慢,因为需要评估整个数据集(即所有行的所有列),尽管这并不是获取行数所必需的。数据集/数据框架API可以大大优化此查询(另请参见https://dev59.com/OVgQ5IYBdhLWcg3weD2E)。 - Raphael Roth
2个回答

11

为什么ds.rdd.count只创建了一个阶段,而ds.count却创建了2个阶段?

两个计数都是有效的两步操作。区别在于,在ds.count的情况下,最终聚合是由一个执行者执行的,而在ds.rdd.count的情况下在驱动程序上聚合最终结果,因此这一步不会反映在DAG中:

另外,当ds.rdd.count只有一个阶段时,为什么它会更慢?

同样的情况。此外,ds.rdd.count必须初始化(并稍后垃圾回收)1亿个Row对象,这几乎是不免费的,并且可能占据了这里时间差异的大部分。

最后,类似于range的对象并不是一个很好的基准测试工具,除非使用时非常小心。根据上下文,对于range的计数可以表示为一个常数时间操作,即使没有显式优化,也可能非常快(例如:spark.sparkContext.range(0, 100000000).count),但不能反映出真实工作负载的性能。

相关链接:如何知道哪个计数查询是最快的?


谢谢您的回复!这是对我的问题的很好的解释。还要感谢您关于 spark.sparkContext.range(0, 100000000).count 的建议。它确实有效。但我的真正问题是使用Spark SQL创建嵌套JSON文件。使用Spark Dataset可以快速完成,但使用RDD则非常麻烦! - himanshuIIITian
2
相关问题:我的理解是否正确,rdd.count将运行分布式作业,而ds.count将把所有数据带到驱动程序?回答自己的问题:这不是真的 :) - Konstantin Kulagin

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接