[英]Add a column to spark dataframe which contains list of all column names of the current row whose value is not null
[英]Spark generate a list of column names that contains(SQL LIKE) a string
下面的這個是使用 SQL Like 功能在特定列中搜索字符串的簡單語法。
val dfx = df.filter($"name".like(s"%${productName}%"))
問題是如何獲取在其 VALUES 中包含特定字符串的每一列 NAME並生成一個新列,其中包含每一行的“列名”列表。
到目前為止,這是我采用的方法,但由於無法在 UDF 中使用 spark-sql“Like”函數而陷入困境。
import org.apache.spark.sql.functions._
import org.apache.spark.sql.DataFrame
import org.apache.spark.sql.types._
import spark.implicits._
val df1 = Seq(
(0, "mango", "man", "dit"),
(1, "i-man", "man2", "mane"),
(2, "iman", "mango", "ho"),
(3, "dim", "kim", "sim")
).toDF("id", "col1", "col2", "col3")
val df2 = df1.columns.foldLeft(df1) {
(acc: DataFrame, colName: String) =>
acc.withColumn(colName, concat(lit(colName + "="), col(colName)))
}
val df3 = df2.withColumn("merged_cols", split(concat_ws("X", df2.columns.map(c=> col(c)):_*), "X"))
這是一個示例輸出。 請注意,這里只有 3 列,但在實際工作中,我將讀取多個可以包含動態列數的表。
+--------------------------------------------+
|id | col1| col2| col3| merged_cols
+--------------------------------------------+
0 | mango| man | dit | col1, col2
1 | i-man| man2 | mane | col1, col2, col3
2 | iman | mango| ho | col1, col2
3 | dim | kim | sim|
+--------------------------------------------+
這可以用做foldLeft
在列一起when
和otherwise
:
val e = "%man%"
val df2 = df1.columns.foldLeft(df.withColumn("merged_cols", lit(""))){(df, c) =>
df.withColumn("merged_cols", when(col(c).like(e), concat($"merged_cols", lit(s"$c,"))).otherwise($"merged_cols"))}
.withColumn("merged_cols", expr("substring(merged_cols, 1, length(merged_cols)-1)"))
所有滿足條件e
列都將附加到merged_cols
列中的字符串。 請注意,該列必須存在才能使第一個 append 工作,以便在發送到foldLeft
時將其添加(包含空字符串)到數據幀中。
在代碼中的最后一排簡單的去除多余的,
那就是在最后。 如果您希望將結果作為數組,只需添加.withColumn("merged_cols", split($"merged_cols", ","))
。
另一種方法是改用UDF
。 這在處理多列時可能是首選,因為foldLeft
將創建多個數據幀副本。 這里使用了正則表達式(不像 SQL,因為它對整列進行操作)。
val e = ".*man.*"
val concat_cols = udf((vals: Seq[String], names: Seq[String]) => {
vals.zip(names).filter{case (v, n) => v.matches(e)}.map(_._2)
})
val df2 = df.withColumn("merged_cols", concat_cols(array(df.columns.map(col(_)): _*), typedLit(df.columns.toSeq)))
注意: typedLit
可以在 Spark 2.2+ 版本中使用,當使用舊版本時,請使用array(df.columns.map(lit(_)): _*)
代替。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.