Dans un projet Spark (2.3.0) utilisant Scala, je voudrais drop plusieurs colonnes en utilisant une expression régulière. J'ai essayé d'utiliser colRegex, mais sans succès:

val df = Seq(("id","a_in","a_out","b_in","b_out"))
  .toDF("id","a_in","a_out","b_in","b_out")

val df_in = df
  .withColumnRenamed("a_in","a")
  .withColumnRenamed("b_in","b")
  .drop(df.colRegex("`.*_(in|out)`"))

// Hoping to get columns Array(id, a, b)
df_in.columns
// Getting Array(id, a, a_out, b, b_out)

En revanche, le mécanisme semble fonctionner avec select:

df.select(df.colRegex("`.*_(in|out)`")).columns
// Getting Array(a_in, a_out, b_in, b_out)

Plusieurs choses ne sont pas claires pour moi:

  1. quelle est cette syntaxe de backquote dans l'expression régulière?
  2. colRegex renvoie un Column: comment peut-il réellement représenter plusieurs colonnes dans le 2ème exemple?
  3. puis-je combiner drop et colRegex ou ai-je besoin d'une solution de contournement?
1
Pierre Gramme 31 août 2020 à 13:57

2 réponses

Meilleure réponse

Si vous vérifiez le code d'étincelle de la méthode colRefex ... il s'attend à ce que les expressions régulières soient passées dans le format ci-dessous

 /** the column name pattern in quoted regex without qualifier */
 val escapedIdentifier = "`(.+)`".r
 /** the column name pattern in quoted regex with qualifier */
 val qualifiedEscapedIdentifier = ("(.+)" + """.""" + "`(.+)`").r

Des backticks (`) sont nécessaires pour entourer votre expression régulière, sinon les modèles ci-dessus n'identifieront pas votre modèle d'entrée.

Vous pouvez essayer de sélectionner des colonnes spécifiques qui sont valides comme mentionné ci-dessous

val df = Seq(("id","a_in","a_out","b_in","b_out"))
  .toDF("id","a_in","a_out","b_in","b_out")

val df_in = df
  .withColumnRenamed("a_in","a")
  .withColumnRenamed("b_in","b")
  .drop(df.colRegex("`.*_(in|out)`"))
val validColumns = df_in.columns.filter(p => p.matches(".*_(in|out)$")).toSeq //select all junk columns
val final_df_in = df_in.drop(validColumns:_*) // this will drop all columns which are not valid as per your criteria.
1
kavetiraviteja 31 août 2020 à 12:41

En plus de la solution de contournement proposée par Waqar Ahmed et kavetiraviteja (réponse acceptée), voici une autre possibilité basée sur select avec quelques expression régulière négative magic. Plus concis, mais plus difficile à lire pour les non-gourous-regex ...

val df_in = df
  .withColumnRenamed("a_in","a")
  .withColumnRenamed("b_in","b")
  .select(df.colRegex("`^(?!.*_(in|out)_).*$`")) // regex with negative lookahead
0
Pierre Gramme 1 sept. 2020 à 12:02