火花过滤器字符串列由包含字符串列表之一

时间:2019-01-13 10:04:37

标签: apache-spark apache-spark-sql

我需要实现类似于Checking if values in List is part of String的功能。即有一个数据框:

abcd_some long strings
goo bar baz

和所需的单词数组,例如["some", "bar"]

带有此代码的UDF可以正常工作,但是,我想更高效些。有没有一种使用SQL DSL表示FILTER my_col CONTAINS ONE OF [items]的方法?也许是通过动态构造REGEX来实现的?

  

注意:这不是常规比赛,而是常规的“包含” /“%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嵌套过滤条件。

2 个答案:

答案 0 :(得分:1)

您的想法正确,但我认为您想使用||而不是or。像这样:

def orFilterGeneratorMultiContains(filterPredicates:Seq[String], column:String): Column = {
  val coi = col(column)
  filterPredicates.map(coi.contains).reduce(_ || _)
}

答案 1 :(得分:0)

在这种情况下rlike不能工作吗?

df.filter(col("foo").rlike(interestingThings.mkString("|"))