Apache spark dropDuplicates运算符中使用了哪一行?

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

使用Spark DF中的
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()
    )