J'ai un Spark trame de données où une colonne est un tableau d'entiers. La colonne est nullable car elle provient d'une jointure externe gauche. Je veux convertir toutes les valeurs nulles en un tableau vide afin Je n'ai pas à m'occuper des null plus tard.
Je pensais que je pouvais le faire comme ça:
val myCol = df("myCol")
df.withColumn( "myCol", when(myCol.isNull, Array[Int]()).otherwise(myCol) )
Cependant, cela entraîne l'exception suivante:
Java.lang.RuntimeException: Unsupported literal type class [I [I@5ed25612
at org.Apache.spark.sql.catalyst.expressions.Literal$.apply(literals.scala:49)
at org.Apache.spark.sql.functions$.lit(functions.scala:89)
at org.Apache.spark.sql.functions$.when(functions.scala:778)
Apparemment, les types de tableaux ne sont pas pris en charge par la fonction when
. Existe-t-il un autre moyen simple de convertir les valeurs nulles?
Dans le cas où cela est pertinent, voici le schéma de cette colonne:
|-- myCol: array (nullable = true)
| |-- element: integer (containsNull = false)
Vous pouvez utiliser un UDF:
import org.Apache.spark.sql.functions.udf
val array_ = udf(() => Array.empty[Int])
combiné avec WHEN
ou COALESCE
:
df.withColumn("myCol", when(myCol.isNull, array_()).otherwise(myCol))
df.withColumn("myCol", coalesce(myCol, array_())).show
Dans la versions récentes vous pouvez utiliser la fonction array
:
import org.Apache.spark.sql.functions.{array, lit}
df.withColumn("foo", array().cast("array<integer>"))
Veuillez noter que cela ne fonctionnera que si la conversion de string
vers le type souhaité est autorisée.
Avec une légère modification de l'approche de zero323, j'ai pu le faire sans utiliser un udf dans Spark 2.3.1.
val df = Seq("a" -> Array(1,2,3), "b" -> null, "c" -> Array(7,8,9)).toDF("id","numbers")
df.show
+---+---------+
| id| numbers|
+---+---------+
| a|[1, 2, 3]|
| b| null|
| c|[7, 8, 9]|
+---+---------+
val df2 = df.withColumn("numbers", coalesce($"numbers", array()))
df2.show
+---+---------+
| id| numbers|
+---+---------+
| a|[1, 2, 3]|
| b| []|
| c|[7, 8, 9]|
+---+---------+
Une alternative sans UDF à utiliser lorsque le type de données dans lequel vous voulez que vos éléments de tableau ne puissent pas être convertis à partir de StringType
est la suivante:
import pyspark.sql.types as T
import pyspark.sql.functions as F
df.withColumn(
"myCol",
F.coalesce(
F.col("myCol"),
F.from_json(F.lit("[]"), T.ArrayType(T.IntegerType()))
)
)
Vous pouvez remplacer IntegerType()
par n'importe quel type de données, également complexes.