如何处理原始可空类型的Spark UDF输入/输出

时间:2017-03-14 16:49:32

标签: sql apache-spark null udf

问题:

1)如果输入是包含null的基本类型的列,则Spark不会调用UDF:

inputDF.show()

+-----+
|  x  |
+-----+
| null|
|  1.0|
+-----+

inputDF
  .withColumn("y",
     udf { (x: Double) => 2.0 }.apply($"x") // will not be invoked if $"x" == null
  )
  .show()

+-----+-----+
|  x  |  y  |
+-----+-----+
| null| null|
|  1.0|  2.0|
+-----+-----+

2)无法从UDF中将null作为基本类型列生成:

udf { (x: String) => null: Double } // compile error

3 个答案:

答案 0 :(得分:6)

相应于the docs

  

请注意,如果使用原始参数,则无法检查   如果它为null,则UDF将为您返回null   原始输入为空。 如果您愿意,请使用盒装类型或[[选项]]   自我处理。


因此,最简单的解决方案就是使用 如果您的UDF输入是基本类型的可空列,则为盒装类型 OR / AND您需要从UDF输出null作为基本类型的列:

inputDF
  .withColumn("y",
     udf { (x: java.lang.Double) => 
       (if (x == null) 1 else null): java.lang.Integer
     }.apply($"x")
  )
  .show()

+-----+-----+
|  x  |  y  |
+-----+-----+
| null| null|
|  1.0|  2.0|
+-----+-----+

答案 1 :(得分:2)

我也会使用Artur的解决方案,但是使用struct还有另一种不使用javas包装类的方法:

import org.apache.spark.sql.functions.struct
import org.apache.spark.sql.Row

inputDF
  .withColumn("y",
     udf { (r: Row) => 
       if (r.isNullAt(0)) Some(1) else None
     }.apply(struct($"x"))
  )
  .show()

答案 2 :(得分:0)

根据SparkSQL: How to deal with null values in user defined function?@zero323提供的解决方案,获得请求结果的另一种方法是:

import scala.util.Try
val udfHandlingNulls udf((x: Double) => Try(2.0).toOption)
inputDF.withColumn("y", udfHandlingNulls($"x")).show()