Considérez le schéma de classe de cas suivant,

case class Y (a: String, b: String)
case class X (dummy: String, b: Y)

Le champ b est facultatif, certains de mes ensembles de données n'ont pas le champ b. Lorsque j'essaie de lire une chaîne JSON qui ne contient pas, je reçois une exception de champ manquant.

spark.read.json(Seq("{'dummy': '1', 'b': {'a': '1'}}").toDS).as[X]
org.apache.spark.sql.AnalysisException: No such struct field b in a;
  at org.apache.spark.sql.catalyst.expressions.ExtractValue$.findField(complexTypeExtractors.scala:85)
  at org.apache.spark.sql.catalyst.expressions.ExtractValue$.apply(complexTypeExtractors.scala:53)
  at org.apache.spark.sql.catalyst.analysis.Analyzer$$anonfun$resolveExpression$1.applyOrElse(Analyzer.scala:1074)
  at org.apache.spark.sql.catalyst.analysis.Analyzer$$anonfun$resolveExpression$1.applyOrElse(Analyzer.scala:1065)
  at org.apache.spark.sql.catalyst.trees.TreeNode$$anonfun$transformUp$2.apply(TreeNode.scala:282)
  at org.apache.spark.sql.catalyst.trees.TreeNode$$anonfun$transformUp$2.apply(TreeNode.scala:282)
  at org.apache.spark.sql.catalyst.trees.CurrentOrigin$.withOrigin(TreeNode.scala:70)

Comment désérialiser automatiquement les champs qui ne sont pas présents dans le JSON pour qu'ils soient null ?

2
kernelman 4 févr. 2020 à 05:12

1 réponse

Meilleure réponse

Définissez le champ b en tant que type Option et utilisez des encodeurs pour créer un schéma de type struct.

  • Passez le schéma défini à l'aide de l'option .schema avec case class X pour créer l'ensemble de données !

Example:

case class Y (a: String, b: Option[String] = None)
case class X (dummy: String, b: Y)

import org.apache.spark.sql.Encoders

val schema = Encoders.product[X].schema

spark.read.schema(schema).json(Seq("{'dummy': '1', 'b': {'a': '1'}}").toDS).as[X].show()

//+-----+----+
//|dummy|   b|
//+-----+----+
//|    1|[1,]|
//+-----+----+

Select b column from struct type:

spark.read.schema(schema).json(Seq("{'dummy': '1', 'b': {'a': '1'}}").toDS).as[X].
select("b.b").show()

//+----+
//|   b|
//+----+
//|null|
//+----+

PrintSchema:

spark.read.schema(schema).json(Seq("{'dummy': '1', 'b': {'a': '1'}}").toDS).as[X].printSchema

//root
 //|-- dummy: string (nullable = true)
 //|-- b: struct (nullable = true)
 //|    |-- a: string (nullable = true)
 //|    |-- b: string (nullable = true)
3
Shu 4 févr. 2020 à 02:37