为啥 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
慢?
【问题讨论】:
AFAIKds.rdd.count
非常慢,因为评估了整个数据集(即所有行的所有列),尽管这对于获取行数并不是必需的。 Dataset/Dataframe API 对这个查询进行了相当大的优化(另见***.com/questions/42714291/…)
【参考方案1】:
为什么 ds.rdd.count 只创建一个阶段而 ds.count 是创建 2 个阶段?
这两个计数实际上都是两步操作。不同之处在于ds.count
的情况下,最终的聚合是由其中一个执行者执行的,而ds.rdd.count
aggregates 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() 快?的主要内容,如果未能解决你的问题,请参考以下文章
为啥这两种 Spark RDD 生成方式具有不同的数据局部性?
当 RDD 包含用户定义的类时,为啥 Apache PySpark top() 会失败?
pyspark - 使用 RDD 进行聚合比 DataFrame 快得多