web-dev-qa-db-ja.com

Spark DataFrameの=== nullとisNullの違い

私が使用しているときの違いに少し混乱しています

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

同じデータフレーム=== nullでカウントを取得していますが、isNullでカウントはゼロです。違いを理解してください。ありがとう

18
John

何よりもまず、互換性の理由で本当に必要な場合を除き、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でそれぞれ。

関連

Apacheにnull値を含めるSpark結合

35
zero323

通常、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]

このフィルター句は無意味に見えます。 && to nullは、これがtrueに解決できないことを保証します。

2番目の説明プランは次のようになります。

== Physical Plan ==
*Filter isnull(c1#2)
+- Scan ExistingRDD[c1#2,c2#3]

ここで、フィルターは期待し、求めているものです。

4
mattinbits