应用于dataframe中空数组列的size函数在溢出后返回1

应用于dataframe中空数组列的size函数在溢出后返回1,dataframe,apache-spark,Dataframe,Apache Spark,注意,在数据帧中的数组列上使用size函数时,使用以下代码-其中包括split: import org.apache.spark.sql.functions.{trim, explode, split, size} val df1 = Seq( (1, "[{a},{b},{c}]"), (2, "[]"), (3, "[{d},{e},{f}]") ).toDF("col1", "col2&

注意,在数据帧中的数组列上使用
size
函数时,使用以下代码-其中包括
split

import org.apache.spark.sql.functions.{trim, explode, split, size}

val df1 = Seq(
  (1, "[{a},{b},{c}]"),
  (2, "[]"),
  (3, "[{d},{e},{f}]")
).toDF("col1", "col2")
df1.show(false)

val df2 = df.withColumn("cola", split(trim($"col2", "[]"), ",")).withColumn("s", size($"cola"))
df2.show(false)
我们得到:

+----+-------------+---------------+---+
|col1|col2         |cola           |s  |
+----+-------------+---------------+---+
|1   |[{a},{b},{c}]|[{a}, {b}, {c}]|3  |
|2   |[]           |[]             |1  |
|3   |[{d},{e},{f}]|[{d}, {e}, {f}]|3  |
+----+-------------+---------------+---+
我希望为0,以便能够区分0或1个条目

这里有一些提示,那里也有一些提示,但没有任何帮助

如果我有以下条目:
(2,null)
,那么我得到的大小是-1,我想这更有用

另一方面,这是从互联网上借来的样本:

val df = Seq("a" -> Array(1,2,3), "b" -> null, "c" -> Array(7,8,9)).toDF("id","numbers")
df.show
val df2 = df.withColumn("numbers", coalesce($"numbers", array()))
df2.show
val df3 = df2.withColumn("s", size($"numbers"))
df3.show()
返回0-如预期的那样

在这里寻找正确的方法,以便得到size=0


我认为根本原因是
split
返回一个空字符串,而不是null

scala> df1.withColumn("cola", split(trim($"col2", "[]"), ",")).withColumn("s", $"cola"(0)).select("s").collect()(1)(0)
res53: Any = ""
当然,包含空字符串的数组的大小是1

为了避免这种情况,也许你可以这样做

val df2 = df1.withColumn("cola", split(trim($"col2", "[]"), ","))
             .withColumn("s", when(length($"cola"(0)) =!= 0, size($"cola"))
                              .otherwise(lit(0)))

df2.show(false)
+----+-------------+---------------+---+
|col1|col2         |cola           |s  |
+----+-------------+---------------+---+
|1   |[{a},{b},{c}]|[{a}, {b}, {c}]|3  |
|2   |[]           |[]             |0  |
|3   |[{d},{e},{f}]|[{d}, {e}, {f}]|3  |
+----+-------------+---------------+---+

此行为继承自,在Scala和Spark中以相同的方式使用。空输入是一种特殊情况,本文对此进行了详细讨论

Spark将
分割
功能的第二个参数(
限制
)设置为-1。从Spark 3开始,我们现在可以传递函数的极限参数

您可以在Scala拆分函数与Spark SQL拆分函数中看到这一点:

“”.split(“”,“”)。长度
//res31:Int=1
sql(““”选择大小(拆分(“,”[,])”)“”)。显示
//+----------------------+
//|大小(拆分(,[,],-1))|
//+----------------------+
//|                     1|
//+----------------------+

“,”.split(“,”).length//不设置limit=-1这将给出空数组
//res33:Int=0
“,”.split(“,”,-1).长度
//res34:Int=2
sql(““”选择大小(拆分(“,”,“[,]”))“”)。显示
//+-----------------------+
//|大小(拆分(、[、]、-1))|
//+-----------------------+
//|                      2|
//+-----------------------+

好吧,假设?我认为这是一个公平的观察。同意吗?是的,我认为如果你从任何非null的东西开始,字符串操作永远不会返回null。我在80年代在uni用pascal研究了字符串包,结果可能是null。这是经典的东西!;)虽然我不认为这是一个好的实现,但我还是要寻找答案。