2017-09-27 14 views
0

Mon application spark lit un fichier csv, le transforme en un format différent avec sql et écrit la donnée de résultat dans un fichier csv différent.Spark traitant des valeurs nulles dans la colonne csv en tant que type de données nul

Par exemple, j'ai csv d'entrée comme suit:

Id|FirstName|LastName|LocationId 
1|John|Doe|123 
2|Alex|Doe|234 

Ma transformation est:

Select Id, 
     FirstName, 
     LastName, 
     LocationId as PrimaryLocationId, 
     null as SecondaryLocationId 
from Input 

(je ne peux pas répondre à pourquoi le nul est utilisé comme SecondaryLocationId, il est entreprise cas d'utilisation) Maintenant spark ne peut pas comprendre le type de données de SecondaryLocationId et renvoie null dans le schéma et renvoie l'erreur La source de données CSV ne prend pas en charge le type de données nul lors de l'écriture dans la sortie csv. Ci-dessous sont printSchema() et les options d'écriture que j'utilise. Voici les options suivantes:

root 
    |-- Id: string (nullable = true) 
    |-- FirstName: string (nullable = true) 
    |-- LastName: string (nullable = true) 
    |-- PrimaryLocationId: string (nullable = false) 
    |-- SecondaryLocationId: null (nullable = true) 

dataFrame.repartition(1).write 
     .mode(SaveMode.Overwrite) 
     .option("header", "true") 
     .option("delimiter", "|") 
     .option("nullValue", "") 
     .option("inferSchema", "true") 
     .csv(outputPath) 

Existe-t-il un moyen de définir par défaut un type de données (tel qu'une chaîne de caractères)? Par ailleurs, je peux obtenir ce travail en remplaçant null avec une chaîne vide ('') mais ce n'est pas ce que je veux faire.

Répondre

0

utilisation éclairée (null):. Org.apache.spark.sql.functions à l'importation {éclairé, udf}

Exemple:

import org.apache.spark.sql.functions.{lit, udf} 

case class Record(foo: Int, bar: String) 
val df = Seq(Record(1, "foo"), Record(2, "bar")).toDF 

val dfWithFoobar = df.withColumn("foobar", lit(null: String)) 


scala> dfWithFoobar.printSchema 
root 
|-- foo: integer (nullable = false) 
|-- bar: string (nullable = true) 
|-- foobar: null (nullable = true) 
and it is not retained by the csv writer. If it is a hard requirement you 
can cast column to the specific type (lets say String): 

import org.apache.spark.sql.types.StringType 
df.withColumn("foobar", lit(null).cast(StringType)) 

ou utiliser une UDF comme ceci:

val getNull = udf(() => None: Option[String]) // Or some other type 

df.withColumn("foobar", getNull()).printSchema 

root 
|-- foo: integer (nullable = false) 
|-- bar: string (nullable = true) 
|-- foobar: string (nullable = true) 

reposant le code zéro323.

permet maintenant discuter de votre deuxième question

Question:

« Ceci est seulement quand je sais quelles colonnes seront traitées datatype comme nuls Lorsqu'un grand nombre de fichiers sont lus et appliqués différents. ? transformations sur, alors je ne sais pas ou est-il un moyen que je pourrais savoir quels champs sont nuls traités "

: Ans

Dans ce cas, vous pouvez utiliser l'option

Les Databricks Scala style guide ne sont pas d'accord que nul ne devrait toujours être interdit de le code Scala et dit: « Pour le code sensible à la performance, préfèrent nulle sur option, afin d'éviter les appels de méthode virtuelle et boxe «

Exemple:.

+------+ 
|number| 
+------+ 
|  1| 
|  8| 
| 12| 
| null| 
+------+ 


val actualDf = sourceDf.withColumn(
    "is_even", 
    when(
    col("number").isNotNull, 
    isEvenSimpleUdf(col("number")) 
).otherwise(lit(null)) 
) 

actualDf.show() 
+------+-------+ 
|number|is_even| 
+------+-------+ 
|  1| false| 
|  8| true| 
| 12| true| 
| null| null| 
+------+-------+ 
+0

Ceci est uniquement lorsque je sais quelles colonnes seront traitées en tant que type de données nul.Quand un grand nombre de fichiers est lu et appliqué diverses transformations, alors je ne saurais pas ou existe-t-il un moyen de savoir quels champs sont traités nuls? – tturner