我的问题的措辞可能令人困惑,所以让我解释一下。说我有一个字符串数组。它们按照最佳案例场景匹配的顺序排列。因此,在索引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()
}
})
答案 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)
与第一种方法不同,它会检查所有模式,但只需要一次操作。