web-dev-qa-db-ja.com

spark:タイムスタンプが最も高い行を維持しながらデータフレームでdropDuplicatesを実行する方法

データフレームの重複行を削除する必要があるユースケースがあります(この場合、重複は同じ「id」フィールドを持っていることを意味します)が、最も高い「timestamp」(unixタイムスタンプ)フィールドを持つ行を維持します。

Drop_duplicateメソッド(私はpysparkを使用しています)を見つけましたが、どのアイテムを保持するかを制御できません。

誰でも助けることができますか?事前にThx

8
arnaud briche

必要な機能を提供するには、手動のマップとリデュースが必要になる場合があります。

def selectRowByTimeStamp(x,y):
    if x.timestamp > y.timestamp:
        return x
    return y

dataMap = data.map(lambda x: (x.id, x))
uniqueData = dataMap.reduceByKey(selectRowByTimeStamp) 

ここでは、IDに基づいてすべてのデータをグループ化しています。次に、グループ化を減らすときは、タイムスタンプが最も高いレコードを保持することによって行います。コードの削減が完了すると、IDごとに1つのレコードのみが残ります。

9
David

あなたはこのようなことをすることができます:

val df = Seq(
  (1,12345678,"this is a test"),
  (1,23456789, "another test"),
  (2,2345678,"2nd test"),
  (2,1234567, "2nd another test")
).toDF("id","timestamp","data")

+---+---------+----------------+
| id|timestamp|            data|
+---+---------+----------------+
|  1| 12345678|  this is a test|
|  1| 23456789|    another test|
|  2|  2345678|        2nd test|
|  2|  1234567|2nd another test|
+---+---------+----------------+

df.join(
  df.groupBy($"id").agg(max($"timestamp") as "r_timestamp").withColumnRenamed("id", "r_id"),
  $"id" === $"r_id" && $"timestamp" === $"r_timestamp"
).drop("r_id").drop("r_timestamp").show
+---+---------+------------+
| id|timestamp|        data|
+---+---------+------------+
|  1| 23456789|another test|
|  2|  2345678|    2nd test|
+---+---------+------------+

timestampに対してidが繰り返される可能性があると予想される場合(以下のコメントを参照)、次のようにすることができます。

df.dropDuplicates(Seq("id", "timestamp")).join(
  df.groupBy($"id").agg(max($"timestamp") as "r_timestamp").withColumnRenamed("id", "r_id"),
  $"id" === $"r_id" && $"timestamp" === $"r_timestamp"
).drop("r_id").drop("r_timestamp").show
5
David Griffin