59 votes

Générer un Spark StructType / Schema à partir d'une classe de cas

Si je voulais créer un StructType (c'est-à-dire un DataFrame.schema ) à partir d'un case class existe-t-il un moyen de le faire sans créer une DataFrame ? Je peux facilement le faire :

case class TestCase(id: Long)
val schema = Seq[TestCase]().toDF.schema

Mais cela semble exagéré de créer une DataFrame alors que tout ce que je veux, c'est le schéma.

(Si vous êtes curieux, la raison de cette question est que je suis en train de définir une UserDefinedAggregateFunction et pour ce faire, il faut surcharger quelques méthodes qui renvoient StructTypes et j'utilise des classes de cas).

89voto

Tzach Zohar Points 6701

Vous pouvez le faire de la même manière SQLContext.createDataFrame le fait :

import org.apache.spark.sql.catalyst.ScalaReflection
val schema = ScalaReflection.schemaFor[TestCase].dataType.asInstanceOf[StructType]

0 votes

Merci je n'avais pas vraiment fait le tour de la question. o.a.s.sql.catalyst encore. Et si j'avais eu les idées claires, j'aurais commencé par createDataFrame comme vous l'avez fait. :-(

0 votes

Super, tu peux même faire ...schemaFor[(Long,Int,Long)]...

0 votes

Pas de soucis - je l'ai trouvé facilement parce que j'ai moi-même essayé quelque chose de similaire il y a quelque temps ;) Et oui - cela fonctionnerait pour n'importe quel Product Merci à Scala !

72voto

Kurt Points 401

Je sais que cette question date de près d'un an, mais je suis tombée dessus et j'ai pensé que d'autres qui le font aussi pourraient vouloir savoir que je viens d'apprendre à utiliser cette approche :

import org.apache.spark.sql.Encoders
val mySchema = Encoders.product[MyCaseClass].schema

3 votes

Attention, le Encoders est marqué avec la balise @Experimental annotation : "An experimental user-facing API". Les API expérimentales peuvent être modifiées ou supprimées dans les versions mineures de Spark, ou être adoptées comme API Spark de première classe." J'ai découvert cela en essayant de déterminer les avantages et les inconvénients des différentes approches (réponse actuelle contre réponse acceptée).

11voto

Art Points 163

Au cas où quelqu'un voudrait faire cela pour un haricot Java personnalisé :

ExpressionEncoder.javaBean(Event.class).schema().json()

2 votes

Il y a aussi Encoders.bean(Event.class).schema() qui, je suppose, fait la même chose.

0 votes

Lorsque je l'utilise pour définir le schéma, je rencontre le problème suivant : la fonction ci-dessus renvoie les membres des données par ordre alphabétique, alors que les colonnes de données du fichier ne le sont pas. Comme elle essaie de faire correspondre l'ordre et non le nom, les données sont corrompues. Avez-vous une idée de la façon de résoudre ce problème ?

5voto

dbaupp Points 20762

Plutôt que de reproduire manuellement la logique de création de l'implicite Encoder qui est transmis à toDF on peut l'utiliser directement (ou, plus précisément, implicitement de la même façon que toDF ) :

// spark: SparkSession

import spark.implicits._

implicitly[Encoder[MyCaseClass]].schema

Malheureusement, cette méthode présente le même problème que l'utilisation de l'option org.apache.spark.sql.catalyst o Encoders comme dans les autres réponses : le site Encoder trait est expérimental.

Comment cela fonctionne-t-il ? Le site toDF méthode sur Seq provient d'un DatasetHolder qui est créé par l'intermédiaire de la méthode implicite localSeqToDatasetHolder qui est importé via spark.implicits._ . Cette fonction est définie comme suit :

implicit def localSeqToDatasetHolder[T](s: Seq[T])(implicit arg0: Encoder[T]): DatasetHolder[T]

Comme vous pouvez le voir, il faut un implicit Encoder[T] qui, pour un case class peut être calculée par newProductEncoder (également importé via spark.implicits._ ). Nous pouvons reproduire cette logique implicite pour obtenir une Encoder pour notre classe de cas, via la commodité scala.Predef.implicitly (dans le champ d'application par défaut, parce qu'il provient de Predef ) qui retournera simplement l'argument implicite demandé :

def implicitly[T](implicit e: T): T

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X