Spark 2.3: вычитать кадры данных, но сохранять повторяющиеся значения (Scala) - PullRequest
0 голосов
/ 23 января 2020

Копирование примера из этого вопроса. В качестве концептуального примера, если у меня есть два кадра данных:

words     = [the, quick, fox, a, brown, fox]
stopWords = [the, a]

, тогда я хочу, чтобы выходные данные были в любом порядке:

words - stopWords = [quick, brown, fox, fox]

ExceptAll может сделать это в 2.4, но я не могу обновить. Ответ в связанном вопросе указан c для фрейма данных:

words.join(stopwords, words("id") === stopwords("id"), "left_outer")
     .where(stopwords("id").isNull)
     .select(words("id")).show()

, так как вам нужно знать pkey и другие столбцы.

Может кто-нибудь придумать ответ это будет работать на любом фрейме данных?

Ответы [ 2 ]

0 голосов
/ 27 января 2020

Оказывается, проще сделать df1.except(df2), а затем объединить результаты с df1, чтобы получить все дубликаты.

Полный код:

def exceptAllCustom(df1: DataFrame, df2: DataFrame): DataFrame = {
    val except = df1.except(df2)

    val columns = df1.columns
    val colExpr: Column = df1(columns.head) <=> except(columns.head)
    val joinExpression = columns.tail.foldLeft(colExpr) { (colExpr, p) =>
        colExpr && df1(p) <=> except(p)
    }

    val join = df1.join(except, joinExpression, "inner")

    join.select(df1("*"))
}
0 голосов
/ 24 января 2020

Вот реализация для всех вас. Я тестировал в Spark 2.4.2, он должен работать на 2.3 тоже (не уверен на 100%)

    val df1 = spark.createDataset(Seq("the","quick","fox","a","brown","fox")).toDF("c1")
    val df2 = spark.createDataset(Seq("the","a")).toDF("c1")

    exceptAllCustom(df1, df2, Seq("c1")).show()


  def exceptAllCustom(df1 : DataFrame, df2 : DataFrame, pks : Seq[String]): DataFrame = {
    val notNullCondition = pks.foldLeft(lit(0==0))((column,cName) => column && df2(cName).isNull)
    val joinCondition = pks.foldLeft(lit(0==0))((column,cName) => column && df2(cName)=== df1(cName))
    val result = df1.join(df2, joinCondition, "left_outer")
       .where(notNullCondition)

    pks.foldLeft(result)((df,cName) => df.drop(df2(cName)))
  }

Результат -

+-----+
|   c1|
+-----+
|quick|
|  fox|
|brown|
|  fox|
+-----+
...