Les jeux de données Spark passent de Row à Encoder
pour Pojo's/primitives. Le moteur Catalyst
utilise une ExpressionEncoder
pour convertir les colonnes dans une expression SQL. Cependant, il ne semble pas exister d'autres sous-classes de Encoder
pouvant être utilisées comme modèle pour nos propres implémentations.
Voici un exemple de code satisfaisant dans Spark 1.X/DataFrames qui n'est pas compilé dans le nouveau régime:
//mapping each row to RDD Tuple
df.map(row => {
var id: String = if (!has_id) "" else row.getAs[String]("id")
var label: String = row.getAs[String]("label")
val channels : Int = if (!has_channels) 0 else row.getAs[Int]("channels")
val height : Int = if (!has_height) 0 else row.getAs[Int]("height")
val width : Int = if (!has_width) 0 else row.getAs[Int]("width")
val data : Array[Byte] = row.getAs[Any]("data") match {
case str: String => str.getBytes
case arr: Array[Byte@unchecked] => arr
case _ => {
log.error("Unsupport value type")
null
}
}
(id, label, channels, height, width, data)
}).persist(StorageLevel.DISK_ONLY)
}
Nous obtenons une erreur de compilation de
Error:(56, 11) Unable to find encoder for type stored in a Dataset.
Primitive types (Int, String, etc) and Product types (case classes) are supported
by importing spark.implicits._ Support for serializing other types will be added in future releases.
df.map(row => {
^
Alors quelque part/quelque part, il devrait y avoir un moyen de
DataFrame
(qui est maintenant un jeu de données de type Row
)Je recherche le code qui effectue ces étapes avec succès.
Pour autant que je sache, rien n'a vraiment changé depuis la version 1.6 et les solutions décrites dans Comment stocker des objets personnalisés dans Dataset? sont les seules options disponibles. Néanmoins, votre code actuel devrait fonctionner correctement avec les encodeurs par défaut pour les types de produits.
Pour savoir pourquoi votre code a fonctionné dans la version 1.x et peut ne pas fonctionner dans la version 2.0.0, vous devez vérifier les signatures. Dans 1.x, DataFrame.map
est une méthode qui prend la fonction Row => T
et transforme RDD[Row]
en RDD[T]
.
Dans la version 2.0.0, DataFrame.map
prend également une fonction de type Row => T
, mais transforme Dataset[Row]
(a.k.a DataFrame
) en Dataset[T]
et T
nécessite donc un Encoder
. Si vous voulez obtenir le "vieux" comportement, vous devriez utiliser RDD
explicitement:
df.rdd.map(row => ???)
Pour Dataset[Row]
map
voir Erreur du codeur lors de la tentative de mappage de la ligne dataframe sur la ligne mise à jour
Avez-vous importé les encodeurs implicites?
importer spark.implicits._
http://spark.Apache.org/docs/2.0.0-preview/api/scala/index.html#org.Apache.spark.sql.Encoder
J'ai importé spark.implicits._ Où spark est SparkSession et a résolu l'erreur. Des encodeurs personnalisés ont été importés.
En outre, l'écriture d'un encodeur personnalisé est une solution que je n'ai pas encore essayée.
Solution de travail: - Créez SparkSession et importez les éléments suivants
importer spark.implicits._