Scala 从Spark DataFrame列中的数组中获取最小值
我有一个带有数组的数据帧Scala 从Spark DataFrame列中的数组中获取最小值,scala,apache-spark,Scala,Apache Spark,我有一个带有数组的数据帧 val DF = Seq( ("123", "|1|2","3|3|4" ), ("124", "|3|2","|3|4" ) ).toDF("id", "complete1", "complete2") .select($"id", split($"complete1", "\\|").as("complete1"), split($"complete2", "\\|").as("complete2")) |id |complete1|c
val DF = Seq(
("123", "|1|2","3|3|4" ),
("124", "|3|2","|3|4" )
).toDF("id", "complete1", "complete2")
.select($"id", split($"complete1", "\\|").as("complete1"), split($"complete2", "\\|").as("complete2"))
|id |complete1|complete2|
+-------------+---------+---------+
| 123| [, 1, 2]|[3, 3, 4]|
| 124| [, 3, 2]| [, 3, 4]|
+-------------+---------+---------+
如何提取每个数组的最小值
|id |complete1|complete2|
+-------------+---------+---------+
| 123| 1 | 3 |
| 124| 2 | 3 |
+-------------+---------+---------+
我已经尝试定义一个UDF来实现这一点,但我得到了一个错误
def minArray(a:Array[String]) :String = a.filter(_.nonEmpty).min.mkString
val minArrayUDF = udf(minArray _)
def getMinArray(df: DataFrame, i: Int): DataFrame = df.withColumn("complete" + i, minArrayUDF(df("complete" + i)))
val minDf = (1 to 2).foldLeft(DF){ case (df, i) => getMinArray(df, i)}
java.lang.ClassCastException: scala.collection.mutable.WrappedArray$ofRef cannot be cast to [Ljava.lang.String;
您可以如下定义您的
udf
函数
def minUdf = udf((arr: Seq[String])=> arr.filterNot(_ == "").map(_.toInt).min)
并称之为
DF.select(col("id"), minUdf(col("complete1")).as("complete1"), minUdf(col("complete2")).as("complete2")).show(false)
应该给你什么
+---+---------+---------+
|id |complete1|complete2|
+---+---------+---------+
|123|1 |3 |
|124|2 |3 |
+---+---------+---------+
已更新
如果传递给udf函数的数组为空或空字符串数组,则会遇到
java.lang.UnsupportedOperationException:empty.min
您应该使用udf
函数as中的if-else
条件来处理该问题
def minUdf = udf((arr: Seq[String])=> {
val filtered = arr.filterNot(_ == "")
if(filtered.isEmpty) 0
else filtered.map(_.toInt).min
})
我希望答案是有帮助的以下是不使用
udf
首先分解使用split()
得到的数组,然后按相同的id分组并找到min
val DF = Seq(
("123", "|1|2","3|3|4" ),
("124", "|3|2","|3|4" )
).toDF("id", "complete1", "complete2")
.select($"id", split($"complete1", "\\|").as("complete1"), split($"complete2", "\\|").as("complete2"))
.withColumn("complete1", explode($"complete1"))
.withColumn("complete2", explode($"complete2"))
.groupBy($"id").agg(min($"complete1".cast(IntegerType)).as("complete1"), min($"complete2".cast(IntegerType)).as("complete2"))
输出:
+---+---------+---------+
|id |complete1|complete2|
+---+---------+---------+
|124|2 |3 |
|123|1 |3 |
+---+---------+---------+
您不需要自定义项,可以使用sort\u array
:
val DF = Seq(
("123", "|1|2","3|3|4" ),
("124", "|3|2","|3|4" )
).toDF("id", "complete1", "complete2")
.select(
$"id",
split(regexp_replace($"complete1","^\\|",""), "\\|").as("complete1"),
split(regexp_replace($"complete2","^\\|",""), "\\|").as("complete2")
)
// now select minimum
DF.
.select(
$"id",
sort_array($"complete1")(0).as("complete1"),
sort_array($"complete2")(0).as("complete2")
).show()
+---+---------+---------+
| id|complete1|complete2|
+---+---------+---------+
|123| 1| 3|
|124| 2| 3|
+---+---------+---------+
请注意,我在拆分之前删除了前导的|
,以避免数组中出现空字符串自Spark 2.4以来,您可以使用来查找数组中的最小值。要使用此函数,首先必须将字符串数组转换为整数数组。强制转换还将通过将空字符串转换为null
值来处理空字符串
DF.选择($“id”,
数组(expr(“cast(complete1作为数组)”).as(“complete1”),
数组(expr(“cast(complete2作为数组)”).as(“complete2”))
这非常有效!如何处理空数组[,,]?java.lang.UnsupportedOperationException:empty.minI在我的数组中没有空字符串。有些只是空的。