Scala distinct()是否对数据集进行排序?
我正在编写一个预处理应用程序,在其他转换和操作中,在将数据集写入HDFS之前对其进行排序。一个新的请求需要我对数据集进行重复数据消除,所以我希望在一个阶段中通过排序来完成。我的理解是,为了有效地执行重复数据消除,排序是必要的(也许我在这方面错了,没有对其进行太多研究,只是看起来很自然) 出于某些原因(Scala distinct()是否对数据集进行排序?,scala,apache-spark,Scala,Apache Spark,我正在编写一个预处理应用程序,在其他转换和操作中,在将数据集写入HDFS之前对其进行排序。一个新的请求需要我对数据集进行重复数据消除,所以我希望在一个阶段中通过排序来完成。我的理解是,为了有效地执行重复数据消除,排序是必要的(也许我在这方面错了,没有对其进行太多研究,只是看起来很自然) 出于某些原因(MapType列在输出模式中),我首先在sort之前的阶段测试了distinct,我认为我会在以后去掉MapType列,以便将它们合并在一起 发生的情况是,跳过了排序的第二阶段,就好像数据集已经排
MapType
列在输出模式中),我首先在sort
之前的阶段测试了distinct
,我认为我会在以后去掉MapType
列,以便将它们合并在一起
发生的情况是,跳过了排序的第二阶段,就好像数据集已经排序一样。这对我来说是有意义的,但文档中的任何地方都不支持(AFAIK),我不知道预期的行为是否稳定(我不想把它推到生产中,只是为了意识到我突然要做两个昂贵的阶段:
sort
和distinct
)。对于如何实现sort
和/或distinct
有更多见解吗?在spark中,distinct
通常所有聚合操作(如groupBy
)都不会对数据进行排序。我们可以使用explain
功能轻松检查这一点
//让我们用[0,4]中的5个元素生成一个df,以便至少有一个副本
val data=spark.范围(5)。选择(地板(rand()*4)为“r”)
data.distinct.explain
==实际计划==
*HashAggregate(键=[r#105L],函数=[])
+-交换哈希分区(r#105L,200)
+-*HashAggregate(键=[r#105L],函数=[])
+-*项目[楼层((兰特(7842501052366484791)*5.0))为r#105L]
+-*范围(0,10,步长=1,分段=2)
HashAggregate
+Exchange
意味着对元素进行散列和洗牌,以使具有相同散列的元素位于同一分区中。然后,对具有相同散列的元素进行比较和重复数据消除。因此,处理后不会对数据进行排序。让我们检查一下:
data.distinct.show()
+---+
|r|
+---+
| 0|
| 3|
| 2|
+---+
现在,让我们谈谈您对性能的担忧。如果您在重复数据消除后进行排序,则会发生以下情况
data.distinct.orderBy(“r”)。解释
==实际计划==
*排序[r#227L ASC NULLS FIRST],true,0
+-Exchange范围分区(r#227L ASC空值优先,200)
+-*HashAggregate(键=[r#227L],函数=[])
+-交换哈希分区(r#227L,200)
+-*HashAggregate(键=[r#227L],函数=[])
+-*项目[楼层((兰特(-8636860894475783181)*4.0))为r#227L]
+-*范围(0,5,步长=1,分段=2)
我们可以看到数据被洗牌以消除重复(Exchange hashpartitioning
),然后再次洗牌以进行排序(Exchange rangepartitioning
)。这相当昂贵。这是因为排序需要按范围进行洗牌,以便同一范围内的元素最终位于同一分区中,然后可以进行排序。但是,我们可以更智能地在重复数据消除之前进行排序:
data.orderBy(“r”).distinct.explain
==实际计划==
*HashAggregate(键=[r#227L],函数=[])
+-*HashAggregate(键=[r#227L],函数=[])
+-*排序[r#227L ASC NULLS FIRST],true,0
+-Exchange范围分区(r#227L ASC空值优先,200)
+-*项目[楼层((兰特(-8636860894475783181)*4.0))为r#227L]
+-*范围(0,5,步长=1,分段=2)
只剩下一次交换。事实上,spark知道在按范围进行洗牌后,重复的元素位于同一分区中。因此它不会触发新的洗牌。能否发布一个最小的代码片段,以便我们了解所有详细信息?我们举个例子,我想知道您是否需要按同一列排序和消除重复,可能是按所有列进行排序…我需要按所有列进行重复数据消除,因为我只需要消除“技术重复项”(在数据转储作业失败并再次启动f.e.)中创建的重复项。但我只按2列进行排序。本质上,我在做类似于
数据集的事情。(一些转换)。排序('id','timestamp')。write.parquet(…)“
我需要将distinct()
放在那里的某个地方。将它放在排序之后并不方便,但如果它有助于提高性能,我会这样做