3
votes

Obtenir la valeur d'une carte pour une valeur de colonne en tant que clé dans les dataframes Spark

Je devais obtenir une valeur d'une carte à partir d'une valeur de colonne comme clé et créer une nouvelle colonne

J'ai essayé ce qui suit

val testMap = Map("abc" -> "1234", "xyz" -> "3456")

def checkthemap (testmap: Map[String, String], key: String) : String = {
    val value = testmap.get(key)
    if (value == null) "" else value.toString
}

val testDF = analysis
    .withColumn("test", lit(checkthemap(testMap,$"col")))

La méthode accepte la chaîne non la colonne. Comment modifier mon instruction withColumn pour envoyer la valeur de la colonne sous forme de chaîne à une méthode.


0 commentaires

3 Réponses :


2
votes

Je suggère d'utiliser une UDF (fonction définie par l'utilisateur) qui prend la colonne comme clé pour la carte de recherche transmise pour renvoyer la valeur de la carte correspondante, comme indiqué ci-dessous:

import org.apache.spark.sql.functions._
import spark.implicits._

def getMapValue(m: Map[String, String], defaultValue: String) = udf{
  (key: String) => m.getOrElse(key, defaultValue)
}

val df = Seq(
  (1, "a"), (2, "b"), (3, "c")
).toDF("id", "key")

val lookupMap = Map("a" -> "xx", "c" -> "zz")

df.withColumn("value", getMapValue(lookupMap, "")($"key")).show
// +---+---+-----+
// | id|key|value|
// +---+---+-----+
// |  1|  a|   xx|
// |  2|  b|     |
// |  3|  c|   zz|
// +---+---+-----+

EDIT: Voir l'autre réponse pour une solution utilisant des fonctions Spark intégrées qui fonctionnent généralement mieux que les UDF.


0 commentaires

10
votes

La réponse acceptée est très inefficace et inutilement compliquée. Au lieu de cela, vous devez simplement traiter testMap comme un littéral. Importez la

df.withColumn("value", coalesce(testMapCol($"col"), lit(""))

conversion suivante de la carte en colonne:

val testMapCol = typedLit(testMap)

et sélectionnez simplement:

import org.apache.spark.sql.functions.{coalesce, lit, typedLit}


2 commentaires

Pour une raison quelconque, je ne souhaite pas créer de mappage vers une colonne ou un dataframe. Je veux y accéder depuis la méthode elle-même. Il y a t'il d'autres solutions?


@ user11425401 tout conseil sur ce problème UDF plz stackoverflow.com/questions/63935600/...



0
votes

Je pense que vous pouvez utiliser la fonction intégrée element_at.

Sa définition est: Renvoie l'élément du tableau à un index donné en valeur si la colonne est un tableau. Renvoie la valeur de la clé donnée en valeur si la colonne est une carte.

import org.apache.spark.sql.functions.{element_at, col, typedLit}
df.withColumn("value", element_at(typedLit(testMap), col("colName")))


0 commentaires