簡體   English   中英

Spark 生成包含(SQL LIKE)字符串的列名列表

[英]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在列一起whenotherwise

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM