【问题标题】:Spark UDF not working with null values in Double fieldSpark UDF 不适用于 Double 字段中的空值
【发布时间】:2017-07-24 16:04:56
【问题描述】:

我正在尝试编写一个 spark UDF,它将 Double 字段的空值替换为 0.0。我正在使用数据集 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 值。

【问题讨论】:

  • 这看起来像 DataFrame API,而不是 Dataset API - myDS 的类型是什么?
  • 这是一个大案例类,其中“rate”字段的类型为 Double。我通过 sourceDF.as[MyCaseClass] 初始化了数据集
  • 查看相关问题 issues.apache.org/jira/browse/SPARK-12648 - 建议允许带有 Option[Double] 的 UDF 作为可空双列(和其他原语)的输入

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


【解决方案1】:

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 /DataFrame)处理 nulls,从性能角度来看,后一种表示是有利的。

一般来说,我建议使用 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] 之前。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-19
    • 2017-01-24
    • 2018-01-25
    • 2014-04-24
    • 1970-01-01
    • 2015-07-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多