我使用以下代码创建数据框:
...
然后我将我的udf应用于它:
val data = List(
List(444.1235D),
List(67.5335D),
List(69.5335D),
List(677.5335D),
List(47.5335D),
List(null)
)
val rdd = sparkContext.parallelize(data).map(Row.fromSeq(_))
val schema = StructType(Array(
StructField("value", DataTypes.DoubleType, true)
))
val df = sqlContext.createDataFrame(rdd, schema)
然后我尝试在此数据集上使用reduce:
val multip: Dataset[Double] = df.select(doubleUdf(df("value"))).as[Double]
在这里我得到了0.0。 我还尝试过滤掉空值
val multipl = multip.reduce(_ * _)
具有相同的结果。 如果我从数据中删除null值,一切正常。如何使用空值减少工作?
我的udf定义如下:
val multipl = multip.filter(_ != null).reduce(_ * _)
答案 0 :(得分:5)
我会强烈假设您的doubleUdf函数将值转换为双精度,而不是使用Option包装器来表示空值,而是将空值转换为0.0。所以,如果你想保持逻辑删除空值,那么过滤掉其他任何东西:
df.na.drop.select(doubleUdf(df("value"))).as[Double]
答案 1 :(得分:2)
首先,我会问你为什么甚至根本不和null
打交道。我会评估我阅读数据的方式,以确保不会发生。
然后我会注意到你可以在内存null
之前删除List
,然后才能达到RDD级别,例如:
data.flatMap(Option(_)).flatten
但是如果你必须在RDD级别处理null
,你有选择(没有双关语):
sparkContext.parallelize(data).filter(!_.contains(null))
或
sparkContext.parallelize(data).map(_.flatMap(Option(_))).filter(_.nonEmpty)
我更喜欢后者。我不喜欢在Scala代码中查看null
。
我会远离基于UDF的解决方案,因为Spark无法优化UDF,而且丢失Spark的优化功能是一种耻辱,而不是像null
那样蹩脚。