Spark DataFrame 中 === null 和 isNull 的区别
Posted
技术标签:
【中文标题】Spark DataFrame 中 === null 和 isNull 的区别【英文标题】:Difference between === null and isNull in Spark DataDrame 【发布时间】:2017-01-08 13:37:49 【问题描述】:我对我们使用时的区别有点困惑
df.filter(col("c1") === null) and df.filter(col("c1").isNull)
我得到计数的相同数据框 === null 但在 isNull 中计数为零。请帮助我理解其中的区别。谢谢
【问题讨论】:
【参考方案1】:首先,不要在 Scala 代码中使用 null
,除非出于兼容性原因确实必须这样做。
关于您的问题,它是纯 SQL。 col("c1") === null
被解释为 c1 = NULL
并且,因为 NULL
标记未定义的值,所以任何值的结果都是未定义的,包括 NULL
本身。
spark.sql("SELECT NULL = NULL").show
+-------------+
|(NULL = NULL)|
+-------------+
| null|
+-------------+
spark.sql("SELECT NULL != NULL").show
+-------------------+
|(NOT (NULL = NULL))|
+-------------------+
| null|
+-------------------+
spark.sql("SELECT TRUE != NULL").show
+------------------------------------+
|(NOT (true = CAST(NULL AS BOOLEAN)))|
+------------------------------------+
| null|
+------------------------------------+
spark.sql("SELECT TRUE = NULL").show
+------------------------------+
|(true = CAST(NULL AS BOOLEAN))|
+------------------------------+
| null|
+------------------------------+
检查NULL
的唯一有效方法是:
IS NULL
:
spark.sql("SELECT NULL IS NULL").show
+--------------+
|(NULL IS NULL)|
+--------------+
| true|
+--------------+
spark.sql("SELECT TRUE IS NULL").show
+--------------+
|(true IS NULL)|
+--------------+
| false|
+--------------+
IS NOT NULL
:
spark.sql("SELECT NULL IS NOT NULL").show
+------------------+
|(NULL IS NOT NULL)|
+------------------+
| false|
+------------------+
spark.sql("SELECT TRUE IS NOT NULL").show
+------------------+
|(true IS NOT NULL)|
+------------------+
| true|
+------------------+
在DataFrame
DSL 中分别实现为Column.isNull
和Column.isNotNull
。
注意:
对于NULL
-safe 比较,使用IS DISTINCT
/ IS NOT DISTINCT
:
spark.sql("SELECT NULL IS NOT DISTINCT FROM NULL").show
+---------------+
|(NULL <=> NULL)|
+---------------+
| true|
+---------------+
spark.sql("SELECT NULL IS NOT DISTINCT FROM TRUE").show
+--------------------------------+
|(CAST(NULL AS BOOLEAN) <=> true)|
+--------------------------------+
| false|
+--------------------------------+
或not(_ <=> _)
/<=>
spark.sql("SELECT NULL AS col1, NULL AS col2").select($"col1" <=> $"col2").show
+---------------+
|(col1 <=> col2)|
+---------------+
| true|
+---------------+
spark.sql("SELECT NULL AS col1, TRUE AS col2").select($"col1" <=> $"col2").show
+---------------+
|(col1 <=> col2)|
+---------------+
| false|
+---------------+
分别在 SQL 和DataFrame
DSL 中。
相关:
Including null values in an Apache Spark Join
【讨论】:
【参考方案2】:通常,了解 Spark Dataframes 中意外结果的最佳方法是查看说明计划。考虑以下示例:
import org.apache.spark.sql.DataFrame, SparkSession
import org.apache.spark.sql.functions._
object Example extends App
val session = SparkSession.builder().master("local[*]").getOrCreate()
case class Record(c1: String, c2: String)
val data = List(Record("a", "b"), Record(null, "c"))
val rdd = session.sparkContext.parallelize(data)
import session.implicits._
val df: DataFrame = rdd.toDF
val filtered = df.filter(col("c1") === null)
println(filtered.count()) // <-- outputs 0, not expected
val filtered2 = df.filter(col("c1").isNull)
println(filtered2.count())
println(filtered2) // <- outputs 1, as expected
filtered.explain(true)
filtered2.explain(true)
第一个解释图显示:
== Physical Plan ==
*Filter (isnotnull(c1#2) && null)
+- Scan ExistingRDD[c1#2,c2#3]
== Parsed Logical Plan ==
'Filter isnull('c1)
+- LogicalRDD [c1#2, c2#3]
这个过滤子句看起来很荒谬。 &&
到 null
确保这永远不会解析为 true
。
第二个解释计划如下:
== Physical Plan ==
*Filter isnull(c1#2)
+- Scan ExistingRDD[c1#2,c2#3]
这里的过滤器是期望和想要的。
【讨论】:
对不起,我无法理解一件事。为什么我在使用 === 时会得到一些记录。怎么可能@mattinbits 您的数据在该列中是否真的有null
?
它有一些空记录(“”),但是当我使用 === null 时,返回的记录数与空字符串不匹配。它将有空记录和非空记录。但是在调用没有空检查的 udf 时出现空指针异常。以上是关于Spark DataFrame 中 === null 和 isNull 的区别的主要内容,如果未能解决你的问题,请参考以下文章
[Spark][Python][DataFrame][RDD]DataFrame中抽取RDD例子