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?
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.
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()
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)
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
}