web-dev-qa-db-fra.com

Comment créer un encodeur personnalisé dans les jeux de données Spark 2.X?

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 

  • Définir/implémenter notre encodeur personnalisé
  • Appliquez-le lors d'un mappage sur la DataFrame (qui est maintenant un jeu de données de type Row)
  • Enregistrez le codeur pour qu'il soit utilisé avec un autre code personnalisé

Je recherche le code qui effectue ces étapes avec succès.

17
javadba

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

17
zero323

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

3
eyal edelman

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._

0
Valan Aravind