通过最新时间戳对Spark DataFrame中的行进行重复数据删除

时间:2018-09-20 17:45:51

标签: apache-spark duplicates apache-spark-sql inner-join

我有一个具有以下架构的DataFrame

root
|- documentId
|- timestamp
|- anotherField

例如,

"d1", "2018-09-20 10:00:00", "blah1"
"d2", "2018-09-20 09:00:00", "blah2"
"d1", "2018-09-20 10:01:00", "blahnew"

请注意,为了便于理解(和我的方便),我将时间戳记显示为字符串。实际上,它是一个long,代表自纪元以来的毫秒数。

如此处所示,存在重复的行(行1和3),这些行具有相同的documentId但具有不同的timestamp(并且可能还有其他字段)。我想对每个timestamp进行重复数据删除并仅保留最新行(基于documentId)。

一个简单的df.groupBy("documentId").agg(max("timestamp), ...)在这里似乎不太可行,因为我不知道如何在与max("timestamp")相符的行中保留其他字段。

因此,我想出了一种复杂的方法。

// first find the max timestamp corresponding to each documentId
val mostRecent = df
    .select("documentId", "timestamp")
      .groupBy("documentId")
        .agg(max("timestamp"))

// now join with the original df on timestamp to retain
val dedupedDf = df.join(mostRecent, Seq("documentId", "timestamp"), "inner")

由此产生的dedupedDf应该仅具有与每个documentId的最新条目相对应的行。

尽管这行得通,但我认为这不是正确的(或有效的)方法,因为我使用的似乎是不必要的join

我该如何做得更好?我正在寻找纯粹的基于“ DataFrame”的解决方案,而不是基于RDD的方法(因为DataBricks的人在一个研讨会上反复告诉我们要使用DataFrames而不是RDD)。

1 个答案:

答案 0 :(得分:3)

请参阅以下代码帮助您实现目标,

val df = Seq(
  ("d1", "2018-09-20 10:00:00", "blah1"),
  ("d2", "2018-09-20 09:00:00", "blah2"),
  ("d1", "2018-09-20 10:01:00", "blahnew")
).toDF("documentId","timestamp","anotherField")

import org.apache.spark.sql.functions.row_number
import org.apache.spark.sql.expressions.Window

val w = Window.partitionBy($"documentId").orderBy($"timestamp".desc)
val Resultdf = df.withColumn("rownum", row_number.over(w))
     .where($"rownum" === 1).drop("rownum")

Resultdf.show()

输入:

+----------+-------------------+------------+
|documentId|          timestamp|anotherField|
+----------+-------------------+------------+
|        d1|2018-09-20 10:00:00|       blah1|
|        d2|2018-09-20 09:00:00|       blah2|
|        d1|2018-09-20 10:01:00|     blahnew|
+----------+-------------------+------------+

输出:

+----------+-------------------+------------+
|documentId|          timestamp|anotherField|
+----------+-------------------+------------+
|        d2|2018-09-20 09:00:00|       blah2|
|        d1|2018-09-20 10:01:00|     blahnew|
+----------+-------------------+------------+