以下是一种简单的语法,可以使用SQL Like功能在特定列中搜索字符串。
<div name="block-0">
<div name="block-1">
<div name="block-2">
<div name="block-3">
问题是我该如何抓取每列NAME中包含特定字符串的列,并生成一个新列,其中包含每一行的那些“列名”。 >
到目前为止,这是我采用的方法,但是由于无法在UDF中使用spark-sql“ Like”函数而陷入困境。
val dfx = df.filter($"name".like(s"%${productName}%"))
这是示例输出。 请注意,这里只有3列,但在实际工作中,我将读取多个表,这些表可以包含动态列数。
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"))
答案 0 :(得分:1)
可以通过在列上使用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
列中的字符串中。请注意,该列必须存在才能使第一个附加项起作用,因此在发送到foldLeft
时会将其添加到数据帧中(包含空字符串)。
代码的最后一行只是删除了最后添加的额外,
。如果您希望将结果作为数组,只需添加.withColumn("merged_cols", split($"merged_cols", ","))
即可。
另一种方法是改用UDF
。当处理许多列时,这可能是首选方法,因为foldLeft
将创建多个数据帧副本。这里使用了正则表达式(而不是像SQL这样的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(_)): _*)
。