SparkSQL: Como lidar com valores nulos na função definida pelo usuário?
Dada a Tabela 1 com uma coluna "x" do tipo String. Eu quero criar a Tabela 2 com uma coluna "y" que é uma representação inteira das seqüências de datas fornecidas em "x".
Essencial é manternull
valores na coluna "y".
Tabela 1 (Dataframe df1):
+----------+
| x|
+----------+
|2015-09-12|
|2015-09-13|
| null|
| null|
+----------+
root
|-- x: string (nullable = true)
Tabela 2 (Dataframe df2):
+----------+--------+
| x| y|
+----------+--------+
| null| null|
| null| null|
|2015-09-12|20150912|
|2015-09-13|20150913|
+----------+--------+
root
|-- x: string (nullable = true)
|-- y: integer (nullable = true)
Enquanto a função definida pelo usuário (udf) para converter valores da coluna "x" para os da coluna "y" é:
val extractDateAsInt = udf[Int, String] (
(d:String) => d.substring(0, 10)
.filterNot( "-".toSet)
.toInt )
e funciona, lidar com valores nulos não é possível.
Mesmo assim, eu posso fazer algo como
val extractDateAsIntWithNull = udf[Int, String] (
(d:String) =>
if (d != null) d.substring(0, 10).filterNot( "-".toSet).toInt
else 1 )
Não encontrei nenhuma maneira de "produzir"null
valores via udfs (é claro, comoInt
s não pode sernull
)
Minha solução atual para criação de df2 (Tabela 2) é a seguinte:
// holds data of table 1
val df1 = ...
// filter entries from df1, that are not null
val dfNotNulls = df1.filter(df1("x")
.isNotNull)
.withColumn("y", extractDateAsInt(df1("x")))
.withColumnRenamed("x", "right_x")
// create df2 via a left join on df1 and dfNotNull having
val df2 = df1.join( dfNotNulls, df1("x") === dfNotNulls("right_x"), "leftouter" ).drop("right_x")
Questões:
A solução atual parece complicada (e provavelmente não é um desempenho eficiente). Existe uma maneira melhor?@ Spark-developers: Existe um tipoNullableInt
planejado / disponível, de modo que o udf a seguir seja possível (consulte o trecho do código)?Trecho de código
val extractDateAsNullableInt = udf[NullableInt, String] (
(d:String) =>
if (d != null) d.substring(0, 10).filterNot( "-".toSet).toInt
else null )