web-dev-qa-db-fra.com

Supprimer tous les enregistrements en double dans la base de données spark

J'ai un dataframe spark avec plusieurs colonnes. Je souhaite connaître et supprimer les lignes contenant des valeurs dupliquées dans une colonne (les autres colonnes peuvent être différentes).

J'ai essayé d'utiliser dropDuplicates(col_name) mais cela ne supprimera que les entrées en double, tout en conservant un enregistrement dans le cadre de données. Ce dont j'ai besoin, c'est de supprimer toutes les entrées contenant initialement des entrées en double. 

J'utilise Spark 1.6 et Scala 2.10.

3
salmanbw

Je voudrais utiliser des fonctions de fenêtre pour cela. Disons que vous voulez supprimer les lignes en double id:

import org.Apache.spark.sql.expressions.Window

df
  .withColumn("cnt", count("*").over(Window.partitionBy($"id")))
  .where($"cnt"===1).drop($"cnt")
  .show()
5
Raphael Roth

Cela peut être fait en regroupant la ou les colonnes pour rechercher les doublons, puis agréger et filtrer les résultats.

Exemple de base de données df:

+---+---+
| id|num|
+---+---+
|  1|  1|
|  2|  2|
|  3|  3|
|  4|  4|
|  4|  5|
+---+---+

Regroupement dans la colonne id pour supprimer ses doublons (les deux dernières lignes):

val df2 = df.groupBy("id")
  .agg(first($"num").as("num"), count($"id").as("count"))
  .filter($"count" === 1)
  .select("id", "num")

Cela vous donnera:

+---+---+
| id|num|
+---+---+
|  1|  1|
|  2|  2|
|  3|  3|
+---+---+

Alternativement, cela peut être fait en utilisant un join. Ce sera plus lent, mais s'il y a beaucoup de colonnes, il n'est pas nécessaire d'utiliser first($"num").as("num") pour chacune d'elles pour les conserver.

val df2 = df.groupBy("id").agg(count($"id").as("count")).filter($"count" === 1).select("id")
val df3 = df.join(df2, Seq("id"), "inner")
2
Shaido

J'ai ajouté une méthode killDuplicates() à la bibliothèque open source spark-daria qui utilise la solution de @Raphael Roth. Voici comment utiliser le code:

import com.github.mrpowers.spark.daria.sql.DataFrameExt._

df.killDuplicates(col("id"))

// you can also supply multiple Column arguments
df.killDuplicates(col("id"), col("another_column"))

Voici l'implémentation du code:

object DataFrameExt {

  implicit class DataFrameMethods(df: DataFrame) {

    def killDuplicates(cols: Column*): DataFrame = {
      df
        .withColumn(
          "my_super_secret_count",
          count("*").over(Window.partitionBy(cols: _*))
        )
        .where(col("my_super_secret_count") === 1)
        .drop(col("my_super_secret_count"))
    }

  }

}

Vous voudrez peut-être utiliser la bibliothèque spark-daria pour garder cette logique en dehors de votre base de code.

0
Powers