spark scala:从数据框中删除连续的(按日期)重复记录

时间:2018-10-01 14:38:27

标签: scala apache-spark dataframe duplicates

问题是关于使用数据框,我想删除完全重复的记录,但不包括某些字段(日期)。 我试图将windowFunction(WindowSpec)用作:

val wFromDupl: WindowSpec = Window
  .partitionBy(comparateFields: _*)
  .orderBy(asc(orderField))

在变量comparateFields中,我存储了所有必须检查的字段(在示例中为DESC1和DESC2),以消除重复的逻辑,如果有重复的记录,我们将丢弃那些日期较高的记录。

在orderField变量中,我只存储了有效日期字段。

因此,通过应用window函数,我要做的是计算一个临时列,为所有重复的记录分配最小的日期,然后将dataFrame筛选为:

 val dfFinal: DataFrame = dfInicial
    .withColumn("w_eff_date", min(col("effective_date")).over(wFromDupl))
  .filter(col("effective_date") === col("w_eff_date")) 
  .drop("w_eff_date")
  .distinct()
  .withColumn("effective_end_date", lead(orderField, 1, "9999-12-31").over(w))

在以下情况下,它可以正常工作:

KEY EFFECTIVE_DATE  DESC 1  DESC 2  W_EFF_DATE (tmp)
E2  2000            A       B       2000
E2  2001            A       B       2000
E2  2002            AA      B       2002

该代码将删除第二条记录:

E2  2001            A       B       2000

但是必须将逻辑应用于连续记录(在日期中),例如,在以下情况下,随着代码的实现,我们将删除第三条记录(DESC1和DESC2相同,并且最小有效日期是2000),但我们不希望这样,因为我们(在eff_date之前)在中间有一个记录(2001 AA B),所以我们想保留这3个记录

KEY EFFECTIVE_DATE  DESC1   DESC2   W_EFF_DATE (tmp)
E1     2000         A       B       2000
E1     2001         AA      B       2001
E1     2002         A       B       2000

对此有何建议? 谢谢大家!

1 个答案:

答案 0 :(得分:0)

一种方法是使用when/otherwise和Window函数lag来确定要保留的行,如下所示:

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

val df = Seq(
  ("E1", "2000", "A",  "B"),
  ("E1", "2001", "AA", "B"),
  ("E1", "2002", "A",  "B"),
  ("E1", "2003", "A",  "B"),
  ("E1", "2004", "A",  "B"),
  ("E2", "2000", "C",  "D"),
  ("E2", "2001", "C",  "D"),
  ("E2", "2002", "CC", "D"),
  ("E2", "2003", "C",  "D")
).toDF("key", "effective_date", "desc1", "desc2")

val compareCols = List("desc1", "desc2")

val win1 = Window.partitionBy("key").orderBy("effective_date")

val df2 = df.
  withColumn("compCols", struct(compareCols.map(col): _*)).
  withColumn("rowNum", row_number.over(win1)).
  withColumn("toKeep",
    when($"rowNum" === 1 || $"compCols" =!= lag($"compCols", 1).over(win1), true).
      otherwise(false)
  )

// +---+--------------+-----+-----+--------+------+------+
// |key|effective_date|desc1|desc2|compCols|rowNum|toKeep|
// +---+--------------+-----+-----+--------+------+------+
// | E1|          2000|    A|    B|   [A,B]|     1|  true|
// | E1|          2001|   AA|    B|  [AA,B]|     2|  true|
// | E1|          2002|    A|    B|   [A,B]|     3|  true|
// | E1|          2003|    A|    B|   [A,B]|     4| false|
// | E1|          2004|    A|    B|   [A,B]|     5| false|
// | E2|          2000|    C|    D|   [C,D]|     1|  true|
// | E2|          2001|    C|    D|   [C,D]|     2| false|
// | E2|          2002|   CC|    D|  [CC,D]|     3|  true|
// | E2|          2003|    C|    D|   [C,D]|     4|  true|
// +---+--------------+-----+-----+--------+------+------+

df2.where($"toKeep").select(df.columns.map(col): _*).
  show
// +---+--------------+-----+-----+
// |key|effective_date|desc1|desc2|
// +---+--------------+-----+-----+
// | E1|          2000|    A|    B|
// | E1|          2001|   AA|    B|
// | E1|          2002|    A|    B|
// | E2|          2000|    C|    D|
// | E2|          2002|   CC|    D|
// | E2|          2003|    C|    D|
// +---+--------------+-----+-----+