Apache spark dropDuplicates运算符中使用了哪一行?
使用Spark DF中的Apache spark dropDuplicates运算符中使用了哪一行?,apache-spark,pyspark,apache-spark-sql,Apache Spark,Pyspark,Apache Spark Sql,使用Spark DF中的dropDuplicates功能时,将保留哪一行?Spark文档中未对其进行说明 保持第一(根据行顺序) 保持最后(根据行顺序) 随机的 p.S.假设在分布式纱线环境中(非主本地)TL;DR保持第一(根据行顺序) dropDuplicates运算符在Spark SQL中 由Spark SQL的Catalyst Optimizer提供的重复数据消除操作符,很好地回答了您的问题(!) 您可以在下面的逻辑计划中看到Deduplicate操作符 // create dataset
dropDuplicates
功能时,将保留哪一行?Spark文档中未对其进行说明
p.S.假设在分布式纱线环境中(非主本地)TL;DR保持第一(根据行顺序)
dropDuplicates
运算符在Spark SQL中
由Spark SQL的Catalyst Optimizer提供的重复数据消除操作符,很好地回答了您的问题(!)
您可以在下面的逻辑计划中看到Deduplicate
操作符
// create datasets with duplicates
val dups = spark.range(9).map(_ % 3)
val q = dups.dropDuplicates
以下是q
dataset的逻辑计划
scala> println(q.queryExecution.logical.numberedTreeString)
00 Deduplicate [value#64L], false
01 +- SerializeFromObject [input[0, bigint, false] AS value#64L]
02 +- MapElements <function1>, class java.lang.Long, [StructField(value,LongType,true)], obj#63: bigint
03 +- DeserializeToObject staticinvoke(class java.lang.Long, ObjectType(class java.lang.Long), valueOf, cast(id#58L as bigint), true), obj#62: java.lang.Long
04 +- Range (0, 9, step=1, splits=Some(8))
在花了一些时间检查Apache Spark的代码之后,dropDuplicates
操作符相当于groupBy
后跟函数
first(columnName:String,ignoreNulls:Boolean):Column聚合函数:返回组中列的第一个值
import org.apache.spark.sql.functions.first
val firsts=dups.groupBy(“值”).agg(第一个(“值”)作为“值”)
scala>println(firsts.queryExecution.logical.numberedTreeString)
00'聚合[值#64L],[值#64L,第一('value,false)作为值#139]
01+-SerializeFromObject[输入[0,bigint,false]作为值#64L]
02+-MapElements,类java.lang.Long,[StructField(value,LongType,true)],obj#63:bigint
03+-DeserializeToObject staticinvoke(类java.lang.Long、对象类型(类java.lang.Long)、valueOf、强制转换(id#58L为bigint)、true)、obj#62:java.lang.Long
04+范围(0,9,阶跃=1,分段=8)
scala>第一解释
==实际计划==
*HashAggregate(键=[value#64L],函数=[first(value#64L,false)])
+-Exchange哈希分区(值#64L,200)
+-*HashAggregate(键=[value#64L],函数=[partial#u first(value#64L,false)])
+-*SerializeFromObject[输入[0,bigint,false]作为值#64L]
+-*MapElements,obj#63:bigint
+-*反序列化对象staticinvoke(类java.lang.Long,对象类型(类java.lang.Long),valueOf,id#58L,true),obj#62:java.lang.Long
+-*范围(0,9,步长=1,分段=8)
我还认为dropDuplicates
操作符可能更有效。除非在dropDuplicates之前也使用coalesce(1)
,否则在删除重复项之前可能会出现意外的顺序。有关示例的完整文档,请参见此处:
我想知道为什么有时候我会得到一个删除了“错误”行的数据帧<代码>合并(1)
解决了问题
编辑:因为有时coalesce(1)
不是一个选项,所以我最喜欢的解决方案是上面帖子中的这个:
from pyspark.sql import Window
from pyspark.sql.functions import rank, col, monotonically_increasing_id
window = Window.partitionBy("col1").orderBy("datestr",'tiebreak')
(df_s
.withColumn('tiebreak', monotonically_increasing_id())
.withColumn('rank', rank().over(window))
.filter(col('rank') == 1).drop('rank','tiebreak')
.show()
)
似乎一个潜在的性能改进是选择无顺序/随机的dropDuplicates,即不执行first@Qmage我不知道第一件是否需要订购。我对此表示怀疑。谢谢你发现了。谢谢你接受这个答案!感谢。@JacekLaskowski您知道如何选择一个随机值而不是第一个值吗?为什么需要它?Spark groupBy()和first()聚合不保留顺序。如果这是drop_duplicates的实现,则不应指望保留任何顺序。
import org.apache.spark.sql.functions.first
val firsts = dups.groupBy("value").agg(first("value") as "value")
scala> println(firsts.queryExecution.logical.numberedTreeString)
00 'Aggregate [value#64L], [value#64L, first('value, false) AS value#139]
01 +- SerializeFromObject [input[0, bigint, false] AS value#64L]
02 +- MapElements <function1>, class java.lang.Long, [StructField(value,LongType,true)], obj#63: bigint
03 +- DeserializeToObject staticinvoke(class java.lang.Long, ObjectType(class java.lang.Long), valueOf, cast(id#58L as bigint), true), obj#62: java.lang.Long
04 +- Range (0, 9, step=1, splits=Some(8))
scala> firsts.explain
== Physical Plan ==
*HashAggregate(keys=[value#64L], functions=[first(value#64L, false)])
+- Exchange hashpartitioning(value#64L, 200)
+- *HashAggregate(keys=[value#64L], functions=[partial_first(value#64L, false)])
+- *SerializeFromObject [input[0, bigint, false] AS value#64L]
+- *MapElements <function1>, obj#63: bigint
+- *DeserializeToObject staticinvoke(class java.lang.Long, ObjectType(class java.lang.Long), valueOf, id#58L, true), obj#62: java.lang.Long
+- *Range (0, 9, step=1, splits=8)
from pyspark.sql import Window
from pyspark.sql.functions import rank, col, monotonically_increasing_id
window = Window.partitionBy("col1").orderBy("datestr",'tiebreak')
(df_s
.withColumn('tiebreak', monotonically_increasing_id())
.withColumn('rank', rank().over(window))
.filter(col('rank') == 1).drop('rank','tiebreak')
.show()
)