web-dev-qa-db-ja.com

Apacheで重複する行(他のすべての列を考慮)のIDを取得するSpark

Spark sqlデータフレームがあり、ID列とn "data"列で構成されています。

_id | dat1 | dat2 | ... | datn
_

id列は一意に決定されますが、_dat1 ... datn_を見ると重複している可能性があります。

私の目標は、それらの重複のidsを見つけることです。

これまでの私のアプローチ:

  • groupByを使用して重複行を取得します:

    dup_df = df.groupBy(df.columns[1:]).count().filter('count > 1')

  • _dup_df_をdf全体と結合して、重複する行を取得しますincludeid

    df.join(dup_df, df.columns[1:])

これは基本的に正しいと確信しています。_dat1 ... datn_列にnull値が含まれているため失敗します。

joinの値に対してnullを実行するには、.eg this SO post 。しかし、これには巨大な値を作成する必要があります。 「文字列結合条件」。

したがって、私の質問:

  1. joins値に対してnullを実行するための単純な/より一般的な/よりPythonicな方法はありますか?
  2. または、さらに良いことに、目的のidsを取得するための別の(より簡単で、より美しい、...)方法はありますか?

ところで:私はSpark 2.1.0およびPython 3.5.3を使用しています

8
Tw UxTLi51Nus

グループあたりの数idsが比較的小さい場合は、groupByおよびcollect_list。必要な輸入品

from pyspark.sql.functions import collect_list, size

データ例:

df = sc.parallelize([
    (1, "a", "b", 3),
    (2, None, "f", None),
    (3, "g", "h", 4),
    (4, None, "f", None),
    (5, "a", "b", 3)
]).toDF(["id"])

クエリ:

(df
   .groupBy(df.columns[1:])
   .agg(collect_list("id").alias("ids"))
   .where(size("ids") > 1))

そして結果:

+----+---+----+------+
|  _2| _3|  _4|   ids|
+----+---+----+------+
|null|  f|null|[2, 4]|
|   a|  b|   3|[1, 5]|
+----+---+----+------+

explodeから返された出力と同等の出力にudfを2回適用する(またはjoinを使用する)ことができます。

グループごとに最小限のidを使用してグループを識別することもできます。いくつかの追加のインポート:

from pyspark.sql.window import Window
from pyspark.sql.functions import col, count, min

ウィンドウ定義:

w = Window.partitionBy(df.columns[1:])

クエリ:

(df
    .select(
        "*", 
        count("*").over(w).alias("_cnt"), 
        min("id").over(w).alias("group"))
    .where(col("_cnt") > 1))

そして結果:

+---+----+---+----+----+-----+
| id|  _2| _3|  _4|_cnt|group|
+---+----+---+----+----+-----+
|  2|null|  f|null|   2|    2|
|  4|null|  f|null|   2|    2|
|  1|   a|  b|   3|   2|    1|
|  5|   a|  b|   3|   2|    1|
+---+----+---+----+----+-----+

さらに、自己結合にgroup列を使用できます。

12
user6910411