Spark UDF在Double字段中不使用空值

时间:2017-07-24 16:04:57

标签: scala apache-spark apache-spark-dataset

我试图编写一个用0.0替换Double字段的空值的spark UDF。我正在使用数据集API。这是UDF:

val coalesceToZero=udf((rate: Double) =>  if(Option(rate).isDefined) rate else 0.0)

这是基于我测试的以下功能正常工作:

def cz(value: Double): Double = if(Option(value).isDefined) value else 0.0

cz(null.asInstanceOf[Double])
cz: (value: Double)Double
res15: Double = 0.0

但是当我以下列方式在Spark中使用它时,UDF无法正常工作。

myDS.filter($"rate".isNull)
    .select($"rate", coalesceToZero($"rate")).show

+----+---------+
|rate|UDF(rate)|
+----+---------+
|null|     null|
|null|     null|
|null|     null|
|null|     null|
|null|     null|
|null|     null|
+----+---------+

然而,以下工作:

val coalesceToZero=udf((rate: Any) =>  if(rate == null) 0.0 else rate.asInstanceOf[Double])

所以我想知道Spark是否有一些处理null Double值的特殊方法。

1 个答案:

答案 0 :(得分:3)

scala.Double不能是null,而您使用的功能似乎只是因为:

scala> null.asInstanceOf[Double]
res2: Double = 0.0

(您可以在If an Int can't be null, what does null.asInstanceOf[Int] mean?)中找到描述此行为的优秀答案。

如果myDS是静态类型数据集,则正确的方法是使用Option[Double]

case class MyCaseClass(rate: Option[Double])

java.lang.Double

case class MyCaseClass(rate: java.lang.Double)

其中任何一个都允许您使用静态类型API(而不是SQL / nulls)处理DataFrame,后者的表示从性能角度来看是有利的。

一般情况下,我建议使用SQL API填充NULLs

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

myDS.withColumn("rate", coalesce($"rate", lit(0.0)))

DataFrameNaFunctions.fill

df.na.fill(0.0, Seq("rate"))
在将Dataset[Row]转换为Dataset[MyCaseClass]之前