web-dev-qa-db-fra.com

Convertir Row en carte en scala d'étincelle

J'ai une ligne d'un bloc de données et je veux la convertir en une carte [String, Any] qui mappe les noms de colonne sur les valeurs de la ligne pour cette colonne.

Y a-t-il un moyen facile de le faire?

Je l'ai fait pour des valeurs de chaîne comme 

def rowToMap(row:Row): Map[String, String] = {
row.schema.fieldNames.map(field => field -> row.getAs[String](field)).toMap
}

val myRowMap = rowToMap(myRow)

Si la ligne contient d'autres valeurs, et non des valeurs spécifiques telles que String, le code devient plus compliqué, car la ligne n'a pas de méthode .get(field).

Des idées?

4
Sorin Bolos

Vous pouvez utiliser getValuesMap:

val df = Seq((1, 2.0, "a")).toDF("A", "B", "C")    
val row = df.first

Pour obtenir Map[String, Any]:

row.getValuesMap[Any](row.schema.fieldNames)
// res19: Map[String,Any] = Map(A -> 1, B -> 2.0, C -> a)

Ou vous pouvez obtenir Map[String, AnyVal] pour ce cas simple puisque les valeurs ne sont pas des objets complexes 

row.getValuesMap[AnyVal](row.schema.fieldNames)
// res20: Map[String,AnyVal] = Map(A -> 1, B -> 2.0, C -> a)

Remarque le type de valeur retourné de la variable getValuesMap peut être désigné comme n'importe quel type. Vous ne pouvez donc pas vous y fier pour déterminer les types de données dont vous disposez mais vous devez garder à l'esprit ce que vous avez depuis le début. 

7
Psidom

Vous pouvez convertir votre dataframe en rdd et utiliser une fonction map simple et utiliser headernames dans la formation MAP de la fonction map et enfin utiliser collect 

val fn = df.schema.fieldNames
val maps = df.rdd.map(row => fn.map(field => field -> row.getAs(field)).toMap).collect()
0
Ramesh Maharjan

Supposons que vous avez une ligne sans informations de structure et que l'en-tête de colonne est un tableau.

val rdd = sc.parallelize( Seq(Row("test1", "val1"), Row("test2", "val2"), Row("test3", "val3"), Row("test4", "val4")) )
rdd.collect.foreach(println)

val sparkFieldNames = Array("col1", "col2")

val mapRDD = rdd.map(
  r => sparkFieldNames.Zip(r.toSeq).toMap
)

mapRDD.collect.foreach(println)
0
Schmitzi

Supposons que vous ayez un cadre de données avec des colonnes [heure (TimeStampType), col1 (DoubleType), col2 (DoubleType)] Vous pouvez faire quelque chose comme ceci:

    val modifiedDf = df.map{row => 
val doubleObject = row.getValuesMap(Seq("col1","col2"))
val timeObject = Map("time" -> row.getAs[TimeStamp]("time"))
val map = doubleObject ++ timeObject
}
0
Naman Agarwal