SparkSQL: как работать с нулевыми значениями в пользовательской функции?
Приведена таблица 1 с одним столбцом «x» типа String. Я хочу создать таблицу 2 со столбцом "у", который является целочисленным представлением строк даты, указанных в "х".
существенный это сохранитьnull
значения в столбце "у".
Таблица 1 (Dataframe df1):
+----------+
| x|
+----------+
|2015-09-12|
|2015-09-13|
| null|
| null|
+----------+
root
|-- x: string (nullable = true)
Таблица 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)
В то время как пользовательская функция (udf) для преобразования значений из столбца "x" в столбец "y" имеет вид:
val extractDateAsInt = udf[Int, String] (
(d:String) => d.substring(0, 10)
.filterNot( "-".toSet)
.toInt )
и работает, имея дело с нулевыми значениями невозможно.
Хотя я могу сделать что-то вроде
val extractDateAsIntWithNull = udf[Int, String] (
(d:String) =>
if (d != null) d.substring(0, 10).filterNot( "-".toSet).toInt
else 1 )
Я не нашел способа «произвести»null
значения через UDFS (конечно, какInt
с не может бытьnull
).
Мое текущее решение для создания df2 (Таблица 2) заключается в следующем:
// 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")
Вопросы:
Текущее решение кажется громоздким (и, вероятно, не эффективным в отношении производительности). Есть ли способ лучше?@ Spark-developers: есть ли типNullableInt
запланировано / доступно, так что возможен следующий udf (см. выдержку из кода)?Выдержка из кода
val extractDateAsNullableInt = udf[NullableInt, String] (
(d:String) =>
if (d != null) d.substring(0, 10).filterNot( "-".toSet).toInt
else null )