Exploser tableau dans apache spark bloc de Données
Je suis en train de les aplatir un schéma de l'existant dataframe avec des champs imbriqués. La Structure de ma dataframe est quelque chose comme ça:
root
|-- Id: long (nullable = true)
|-- Type: string (nullable = true)
|-- Uri: string (nullable = true)
|-- Type: array (nullable = true)
| |-- element: string (containsNull = true)
|-- Gender: array (nullable = true)
| |-- element: string (containsNull = true)
Type et le sexe peut contenir de nombreux éléments, un élément ou une valeur null.
J'ai essayé d'utiliser le code suivant:
var resDf = df.withColumn("FlatType", explode(df("Type")))
Mais comme un résultat, en partant, d'un bloc de données, je lâche les lignes pour lesquelles j'ai eu des valeurs null dans la colonne Type. Cela signifie, par exemple, si j'ai 10 lignes et 7 lignes de type est nul et 3 type n'est pas null, après j'utilise exploser en résultant bloc de données, je n'ai que trois lignes.
Comment puis-je garder les lignes avec des valeurs nulles mais exploser tableau de valeurs?
J'ai trouvé une sorte de solution de contournement, mais encore coincé dans un seul endroit. Pour les types standard, nous pouvons effectuer les opérations suivantes:
def customExplode(df: DataFrame, field: String, colType: String): org.apache.spark.sql.Column = {
var exploded = None: Option[org.apache.spark.sql.Column]
colType.toLowerCase() match {
case "string" =>
val avoidNull = udf((column: Seq[String]) =>
if (column == null) Seq[String](null)
else column)
exploded = Some(explode(avoidNull(df(field))))
case "boolean" =>
val avoidNull = udf((xs: Seq[Boolean]) =>
if (xs == null) Seq[Boolean]()
else xs)
exploded = Some(explode(avoidNull(df(field))))
case _ => exploded = Some(explode(df(field)))
}
exploded.get
}
Et après que juste l'utiliser comme ceci:
val explodedField = customExplode(resultDf, fieldName, fieldTypeMap(field))
resultDf = resultDf.withColumn(newName, explodedField)
Cependant, j'ai un problème de type struct pour ce type de structure:
|-- Address: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- AddressType: array (nullable = true)
| | | |-- element: string (containsNull = true)
| | |-- DEA: array (nullable = true)
| | | |-- element: struct (containsNull = true)
| | | | |-- Number: array (nullable = true)
| | | | | |-- element: string (containsNull = true)
| | | | |-- ExpirationDate: array (nullable = true)
| | | | | |-- element: timestamp (containsNull = true)
| | | | |-- Status: array (nullable = true)
| | | | | |-- element: string (containsNull = true)
Comment traiter ce genre de schéma lorsque le DEA est null?
Vous en remercie d'avance.
P. S. j'ai essayé d'utiliser des vues Latérales, mais le résultat est le même.
OriginalL'auteur Artem | 2016-09-11
Vous devez vous connecter pour publier un commentaire.
Peut-être vous pouvez essayer d'utiliser
when
:Comme indiqué dans le
when
de la fonction de la documentation, la valeurnull
est inséré pour les valeurs qui ne correspondent pas aux conditions.vous avez raison, je suis désolé. Est un
union
une option pour vous? Vous pourriez fairedf.where($"Type".isNull).withColumn("FlatType", lit(null)).unionAll(df.withColumn("FlatType", explode($"Type")))
oui, merci, j'ai pensé à cette option, mais je suis de construction d'un algorithme générique pour l'aplatissement de schéma et j'ai peur que l'union peut être vraiment lent. J'espère trouver une meilleure solution, mais l'union est une option de sauvegarde pour moi.
OriginalL'auteur Daniel de Paula