如何获取在数据框中最终匹配的排名最高的过滤条件?

时间:2018-05-17 15:44:08

标签: scala apache-spark

我的问题的措辞可能令人困惑,所以让我解释一下。说我有一个字符串数组。它们按照最佳案例场景匹配的顺序排列。因此,在索引0处,我们希望它始终存在于dataframe列中,但如果它不存在则则索引1是下一个最佳选项。我已经写过这样的逻辑,但我觉得这不是最有效的方法。有没有其他方法可以做得更好?

数据集非常小,但我担心这不能很好地扩展。

val df = spark.createDataFrame(data)

val nameArray = Array[String]("Name", "Name%", "%Name%", "Person Name", "Person Name%", "%Person Name%")

nameArray.foreach(x => {
  val nameDf = df.where("text like '" + x + "'")

  if(nameDf.count() > 0){
    nameDf.show(1)
    break()
  }
})

1 个答案:

答案 0 :(得分:1)

如果值是根据偏好从左(最高优先级)到右(最低优先级)排序,而较低优先级模式已经覆盖了更高优先级(它不像你的例子中的情况那样)你生成像这样的表达

import org.apache.spark.sql._

def matched(df: DataFrame, nameArray: Seq[String], c: String = "text") = {

  val matchIdx = nameArray.zipWithIndex.foldRight(lit(-1)){
    case ((s, i), acc) => when(col(c) like s, lit(i)).otherwise(acc)
  }

  df.select(max(matchIdx)).first match {
    case Row(-1)     => None  // No pattern matches all records
    case Row(i: Int) => Some(nameArray(i))
  }
}

用法示例:

matched(Seq("Some Name", "Name", "Name Surname").toDF("text"), Seq("Name", "Name%", "%Name%"))
// Option[String] = Some(%Name%)

这种方法有两个优点:

  • 只需要一个操作。
  • 模式匹配可以短路。

如果不满足前提条件,您可以

import org.apache.spark.sql.functions._

val unmatchedCount: Map[String, Long] = df.select(
  nameArray.map(s => count(when(not($"text" like s), 1)).alias(s)): _*
).first.getValuesMap[Long](nameArray)

与第一种方法不同,它会检查所有模式,但只需要一次操作。