【问题标题】:Difference between === null and isNull in Spark DataDrameSpark DataFrame 中 === null 和 isNull 的区别
【发布时间】:2017-05-22 20:16:27
【问题描述】:

我对我们使用时的区别有点困惑

 df.filter(col("c1") === null) and df.filter(col("c1").isNull) 

我得到计数​​的相同数据框 === null 但在 isNull 中计数为零。请帮助我理解其中的区别。谢谢

【问题讨论】:

    标签: sql scala apache-spark dataframe apache-spark-sql


    【解决方案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 时出现空指针异常。
      猜你喜欢
      • 1970-01-01
      • 2012-09-26
      • 1970-01-01
      • 2022-06-11
      • 2019-12-25
      • 2021-11-19
      • 2017-10-08
      • 2017-05-11
      相关资源
      最近更新 更多