为啥 dataset.count() 比 rdd.count() 快?

Posted

技术标签:

【中文标题】为啥 dataset.count() 比 rdd.count() 快?【英文标题】:Why dataset.count() is faster than rdd.count()?为什么 dataset.count() 比 rdd.count() 快? 【发布时间】:2017-05-13 06:29:35 【问题描述】:

我创建了一个 Spark Dataset[Long]

scala> val ds = spark.range(100000000)
ds: org.apache.spark.sql.Dataset[Long] = [id: bigint]

当我运行ds.count 时,它给了我0.2s 的结果(在 4 核 8GB 机器上)。另外,它创建的DAG如下:

但是,当我运行ds.rdd.count 时,它给了我4s 的结果(同一台机器)。但它创建的DAG如下:

所以,我的疑问是:

    为什么ds.rdd.count 只创建一个阶段,而ds.count 则创建两个阶段? 另外,当ds.rdd.count 只有一个阶段时,为什么它比有两个阶段的ds.count 慢?

【问题讨论】:

AFAIK ds.rdd.count 非常慢,因为评估了整个数据集(即所有行的所有列),尽管这对于获取行数并不是必需的。 Dataset/Dataframe API 对这个查询进行了相当大的优化(另见***.com/questions/42714291/…) 【参考方案1】:

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

这两个计数实际上都是两步操作。不同之处在于ds.count的情况下,最终的聚合是由其中一个执行者执行的,而ds.rdd.countaggregates the final result on the driver,因此这一步没有反映在DAG中:

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

同上。此外,ds.rdd.count 必须初始化(以及后来的垃圾收集)1 亿个 Row 对象,这几乎是免费的,并且可能占这里时间差的大部分。

最后range-like 对象不是一个好的基准测试工具,除非非常谨慎地使用。根据上下文,超出范围的计数可以表示为恒定时间操作,即使没有显式优化也可以非常快(参见例如spark.sparkContext.range(0, 100000000).count),但不能反映实际工作负载的性能。

相关:How to know which count query is the fastest?

【讨论】:

感谢您的回复!这是对我的问题的一个很好的解释。并感谢您对spark.sparkContext.range(0, 100000000).count 的建议。它确实有效。但我真正的问题是使用 Spark SQL 创建嵌套的 JSON 文件。使用 Spark 数据集我可以快速完成,但使用 RDD 真的很痛苦! 相关问题:我的理解是否正确,rdd.count 将运行分布式作业,但是 ds.count 会将所有数据带到驱动程序?回答我自己的问题:这不是真的:)

以上是关于为啥 dataset.count() 比 rdd.count() 快?的主要内容,如果未能解决你的问题,请参考以下文章

(为啥)我们需要在 RDD 上调用缓存还是持久化

为啥这两种 Spark RDD 生成方式具有不同的数据局部性?

当 RDD 包含用户定义的类时,为啥 Apache PySpark top() 会失败?

pyspark - 使用 RDD 进行聚合比 DataFrame 快得多

为啥 RDD[Row].map 中的 getInt 会给出“错误:值 getInt 不是 Any 的成员”?

是否有任何性能问题迫使在 spark 中使用 count 进行急切评估?