访问数据框Row
的值时如何处理Null? Null指针异常是否真的需要手动处理?必须有更好的解决方案。
case class FirstThing(id:Int, thing:String, other:Option[Double])
val df = Seq(FirstThing(1, "first", None), FirstThing(1, "second", Some(2)), FirstThing(1, "third", Some(3))).toDS
df.show
val list = df.groupBy("id").agg(collect_list(struct("thing", "other")).alias("mylist"))
list.show(false)
这对于NPE失败:
val xxxx = udf((t:Seq[Row])=> t.map(elem => elem.getDouble(1)))
list.withColumn("aa", xxxx(col("mylist"))).show(false)
这奇怪地给出了0:
val xxxx = udf((t:Seq[Row])=> t.map(elem => elem.getAs[Double]("other")))
list.withColumn("aa", xxxx(col("mylist"))).show(false)
+---+-----------------------------------------+---------------+
|id |mylist |aa |
+---+-----------------------------------------+---------------+
|1 |[[first,null], [second,2.0], [third,3.0]]|[0.0, 2.0, 3.0]|
+---+-----------------------------------------+---------------+
可悲的是,这种适用于数据帧/数据集的方法也失败了:
val xxxx = udf((t:Seq[Row])=> t.map(elem => elem.getAs[Option[Double]]("other")))
list.withColumn("aa", xxxx(col("mylist"))).show(false)
ClassCastException:无法将java.lang.Double强制转换为scala.Option
答案 0 :(得分:1)
使用getAs[Double]
并将其包装在Option
中将得到预期的结果:
val xxxx = udf((t: Seq[Row])=> t.map(elem => Option(elem.getAs[Double]("other"))))
list.withColumn("aa", xxxx($"mylist")).show(false)
+---+-----------------------------------------+----------------+
|id |mylist |aa |
+---+-----------------------------------------+----------------+
|1 |[[first,null], [second,2.0], [third,3.0]]|[null, 2.0, 3.0]|
+---+-----------------------------------------+----------------+
getAs[Option[Double]]
不起作用的原因可能是因为数据框架构不了解列具有选项。 udf之前的架构:
root
|-- id: integer (nullable = false)
|-- mylist: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- thing: string (nullable = true)
| | |-- other: double (nullable = true)