我需要实现类似于以下内容: 检查列表中的值是否是 Spark 中字符串的一部分。 即有一个数据帧:
abcd_some long strings
goo bar baz
和一系列所需的单词,例如 ["some", "bar"]
.
带有此代码的 UDF 可以正常工作,但是,我希望有更高效的东西。有没有办法使用 SQL DSL 表达FILTER my_col CONTAINS ONE OF [items]
?也许通过动态构建正则表达式?
注意:它不是exat匹配,而是常规的"包含"/喜欢"%thing%"。 即不完全匹配。否则,
isIn
运算符将起作用。
编辑
可能动态生成一些SQL代码是最有效的方法。
def orFilterGeneratorMultiContains(filterPredicates:Seq[String], column:String):Column = {
col(column).contains(filterPredicates(0)) or col(column).contains(filterPredicates(1)) // TODO iterate
}
def filterToDesiredApps(filterPredicates:Seq[String], column:String)(df:DataFrame):DataFrame={
df.filter(orFilterGeneratorMultiContains(filterPredicates, column))
}
因此,仍然需要弄清楚如何正确迭代表达式。
编辑 2
但是,事实证明这有点棘手:
import org.apache.spark.sql.functions.col
val column = col("foo")
val interstingTHings = Seq("bar", "baz", "thing3")
interstingTHings.foldLeft(column) { (filteredOrColumnExpression, predicateItem) =>
// TODO how to properly nest the OR operator?
// filteredOrColumnExpression.contains(predicateItem) // generates: Contains(Contains(Contains('foo, bar), baz), thing3)
filteredOrColumnExpression or filteredOrColumnExpression.contains(predicateItem) // generates: ((('foo || Contains('foo, bar)) || Contains(('foo || Contains('foo, bar)), baz)) || Contains((('foo || Contains('foo, bar)) || Contains(('foo || Contains('foo, bar)), baz)), thing3))
// TODO but what y really would need is:
// col(column).contains("bar") or col(column).contains("baz") or col(column).contains("thing3")
}.explain(true)
因为它不会生成正确的嵌套OR
筛选条件。
不喜欢吗?
df.filter(col("foo").rlike(interestingThings.mkString("|"))
您的想法是正确的,但我认为您想使用||
而不是or
.像这样:
def orFilterGeneratorMultiContains(filterPredicates:Seq[String], column:String): Column = {
val coi = col(column)
filterPredicates.map(coi.contains).reduce(_ || _)
}