Spark UDF 不适用于 Double 字段中的空值

Jit*_*t B 4 scala apache-spark apache-spark-dataset

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

val coalesceToZero=udf((rate: Double) =>  if(Option(rate).isDefined) rate else 0.0)
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

但是当我以下列方式在 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|
+----+---------+
Run Code Online (Sandbox Code Playgroud)

但是,以下工作:

val coalesceToZero=udf((rate: Any) =>  if(rate == null) 0.0 else rate.asInstanceOf[Double])
Run Code Online (Sandbox Code Playgroud)

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

zer*_*323 5

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

scala> null.asInstanceOf[Double]
res2: Double = 0.0
Run Code Online (Sandbox Code Playgroud)

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

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

case class MyCaseClass(rate: Option[Double])
Run Code Online (Sandbox Code Playgroud)

java.lang.Double

case class MyCaseClass(rate: java.lang.Double)
Run Code Online (Sandbox Code Playgroud)

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

一般来说,我建议NULLs使用 SQL API 进行填充:

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

myDS.withColumn("rate", coalesce($"rate", lit(0.0)))
Run Code Online (Sandbox Code Playgroud)

DataFrameNaFunctions.fill

df.na.fill(0.0, Seq("rate"))
Run Code Online (Sandbox Code Playgroud)

在转换Dataset[Row]Dataset[MyCaseClass].