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.isNullColumn.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(_ &lt;=&gt; _)/&lt;=&gt;

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]

这个过滤子句看起来很荒谬。 &amp;&amp;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例子

Spark中RDD和Dataframe有啥区别

在 Apache Spark 中拆分 DataFrame

Spark:减去两个DataFrame

Spark (Scala) - 在 DataFrame 中恢复爆炸

如何在 Spark 的空 Dataframe 中添加行记录