在Apache Spark中

时间:2017-03-29 13:30:10

标签: apache-spark pyspark apache-spark-sql pyspark-sql

我有一个Spark sql数据帧,包含ID列和n"数据"列,即

id | dat1 | dat2 | ... | datn

id列是唯一确定的,而查看dat1 ... datn则可能存在重复。

我的目标是找到这些重复项的id

到目前为止我的方法:

  • 使用groupBy获取重复的行:

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

  • dup_df加入整个df以获取重复的行,包括 id

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

我确信这基本上是正确的,但由于dat1 ... datn列包含null值,因此失败了。

要对join值进行null,我找到.e.g this SO post。但这需要构建一个巨大的字符串连接条件"。

因此我的问题:

  1. 是否有一种简单/更通用/更pythonic的方法可以对joins值进行null
  2. 或者,更好的是,是否有另一种(更简单,更美丽,...)方法来获得所需的id
  3. BTW:我使用的是Spark 2.1.0和Python 3.5.3

1 个答案:

答案 0 :(得分:12)

如果每个组的数量ids相对较小,您可以groupBycollect_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)应用于与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列进行自我加入。