Je suis un peu confus avec la différence lorsque nous utilisons
df.filter(col("c1") === null) and df.filter(col("c1").isNull)
Même trame de données que je reçois des comptes dans === null mais zéro compte dans isNull. Veuillez m'aider à comprendre la différence. Merci
D'abord et avant tout, n'utilisez pas null
dans votre code Scala sauf si vous en avez vraiment besoin pour des raisons de compatibilité.
Concernant votre question, c'est du SQL simple. col("c1") === null
est interprété comme c1 = NULL
et, parce que NULL
marque des valeurs non définies, le résultat n'est pas défini pour toute valeur incluant NULL
elle-même.
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|
+------------------------------+
Les seules méthodes valides pour vérifier NULL
sont:
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|
+------------------+
implémenté dans DataFrame
DSL comme Column.isNull
et Column.isNotNull
respectivement.
Remarque :
Pour NULL
- des comparaisons sûres, utilisez 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|
+--------------------------------+
ou 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|
+---------------+
en SQL et DataFrame
DSL respectivement.
Connexes :
Habituellement, la meilleure façon de faire la lumière sur des résultats inattendus dans Spark Dataframes est de regarder le plan d'explication. Prenons l'exemple suivant:
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)
}
Le premier plan d'explication montre:
== Physical Plan ==
*Filter (isnotnull(c1#2) && null)
+- Scan ExistingRDD[c1#2,c2#3]
== Parsed Logical Plan ==
'Filter isnull('c1)
+- LogicalRDD [c1#2, c2#3]
Cette clause de filtre semble absurde. Le &&
à null
garantit que cela ne pourra jamais être résolu en true
.
Le deuxième plan d'explication ressemble à ceci:
== Physical Plan ==
*Filter isnull(c1#2)
+- Scan ExistingRDD[c1#2,c2#3]
Ici, le filtre est ce que vous attendez et ce que vous voulez.