столбец строки искрового фильтра by содержит одну из списка строк - PullRequest
0 голосов
/ 13 января 2019

Мне нужно добиться чего-то похожего на: Проверка, являются ли значения в List частью String в искре. То есть существует датафрейм:

abcd_some long strings
goo bar baz

и массив желаемых слов, таких как ["some", "bar"].

UDF с этим кодом будет работать нормально, но мне бы хотелось иметь что-то более эффективное. Есть ли способ выразить FILTER my_col CONTAINS ONE OF [items] с помощью SQL DSL? Возможно, путем динамического построения REGEX?

ПРИМЕЧАНИЕ: это не совпадение, а обычное 'CONTAINS' / LIKE '% 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 вложенные условия фильтрации.

1 Ответ

0 голосов
/ 13 января 2019

У вас правильная идея, но я думаю, что вы хотите использовать ||, а не or. Что-то вроде:

def orFilterGeneratorMultiContains(filterPredicates:Seq[String], column:String): Column = {
  val coi = col(column)
  filterPredicates.map(coi.contains).reduce(_ || _)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...