Scala Dataframe对列进行空检查

Sub*_*ade 8 scala dataframe apache-spark apache-spark-sql

val new_df = df.filter($"type_interne" !== "" || $"type_interne" !== "null")
Run Code Online (Sandbox Code Playgroud)

给我错误值||不是字符串的成员

当我使用===适合过滤器

val new_df = df.filter($"type_interne" === "" || $"type_interne" === "null")
Run Code Online (Sandbox Code Playgroud)

Rap*_*oth 9

问题似乎是运算符优先级,尝试使用大括号:

 val new_df = df.filter(($"type_interne" !== "") || ($"type_interne" !== null))
Run Code Online (Sandbox Code Playgroud)

你也可以像这样写:

val new_df = df.filter(($"type_interne" !== "") or $"type_interne".isNotNull)
Run Code Online (Sandbox Code Playgroud)

  • 使用=!=作为最新版本。 (2认同)

Nik*_*ita 7

尽管在撰写本文时 Raphael 的答案是完全正确的,但 Spark 正在进化... Operator!==自 2.0 版以来已被弃用,但您可以使用=!=which 解决上述优先级问题,而无需使用括号。源码见相应注释:https : //github.com/apache/spark/blob/branch-2.2/sql/core/src/main/scala/org/apache/spark/sql/Column.scala#L319-L320

详细回答:
我还想指出一些一开始对我来说并不明显的东西。有 DataFrame (DF) 和 DataSet (DS) 的概念,它们也将它们在上述上下文中的用法分为:
1) 由催化剂解释的字符串(错误仅在运行时捕获)-DF 和 DS 案例类 NullStrings( n:整数,s:字符串)

val df = spark.sparkContext.parallelize(Seq(
    (1, "abc"),
    (2, "ABC"),
    (3, null),
    (4, ""))
).toDF("n", "s")

df.filter("s is not null and s != ''").show()

+---+---+
|  n|  s|
+---+---+
|  1|abc|
|  2|ABC|
+---+---+
Run Code Online (Sandbox Code Playgroud)

2)使用Column概念($spark.implicits._导入)的数据帧语法部分编译检查:

df.filter($"s" =!= "" || $"s" =!= null).show() 
Run Code Online (Sandbox Code Playgroud)

但实际上=!=忽略了空值(请参阅<=>空值安全比较),因此下面等于

df.filter($"s" =!= "").show()

+---+---+
|  n|  s|
+---+---+
|  1|abc|
|  2|ABC|
+---+---+
Run Code Online (Sandbox Code Playgroud)

3) 数据集

val ds = df.as[NullStrings]

ds.filter(r => r.s != null && r.s.nonEmpty).show()
+---+---+
|  n|  s|
+---+---+
|  1|abc|
|  2|ABC|
+---+---+
Run Code Online (Sandbox Code Playgroud)

请注意,如果您Option在 case 类中使用,则必须处理它,而不是简单的字符串。

case class NullStringsOption(n: Int, s: Option[String])

val ds1 = df.as[NullStringsOption]

ds1.filter(_.s.exists(_.nonEmpty)).show()
Run Code Online (Sandbox Code Playgroud)