【问题标题】:Check if value from one dataframe column exists in another dataframe column using Spark Scala使用 Spark Scala 检查一个数据框列中的值是否存在于另一个数据框列中
【发布时间】:2019-07-16 04:46:46
【问题描述】:

我有 2 个数据框 df1 和 df2,

df1 的列名称包含 a、b、c 等值 df2 的列 ID 的值类似于 a,b

如果df1 中的Name 列与df2 中的Id 列匹配,那么我们需要匹配状态为0。如果没有匹配,我们需要匹配状态为1。 我知道我可以使用 collect 将 df2 ID 列放入集合中,然后检查 df1 中的 Name 列是否有匹配的条目。

val df1 = Seq(“Rey”, “John”).toDF(“Name”)
val df2 = Seq(“Rey”).toDF(“Id”)

val collect = df2.select("Id").map(r => r.getString(0)).collect.toList 

类似的,

    val df3 = 
    df1.withColumn("match_sts",when(df1("Name").isin(collect).then(0).else(1)))

Expected output
+ — — + — -+
|Name|match_sts|
+ — — + — -+
| Rey| 0  |
|John| 1  |
+ — — + — -+

但我不想在这里使用收集。有没有其他可用的方法。

【问题讨论】:

  • 可能是一个例子和你自己的尝试?可以使用带有 EXISTS 或外连接的 spark sql...
  • 正如 thebluephantom 所说,请分享您的尝试或至少是您的数据框示例。
  • @thebluephantom 分享了这个方法,我不想为 df1 和 df2 做一个联接
  • 确实如此,但您需要采取某种行动来获得所谓的副作用。啊哈,但你的收藏有多大?
  • @thebluephantom 应该少于 10 万行

标签: scala apache-spark


【解决方案1】:

collect 不是你想要的,但它是 DF col --> 列表转换的一个众所周知的问题。如果不是一个巨大的列表,那么你可以这样做 - 这实际上是有效的,你也可以广播 inlist:

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

val df1 = Seq("Rey", "John", "Donald", "Trump").toDF("Name")
val df2 = Seq("Rey", "Donald").toDF("Id")

val inlist = df2.select("Id").map(r => r.getString(0)).collect.toList

val df3 = df1.withColumn("match_status", when(df1("Name").isin(inlist: _*),1).otherwise(0))
df3.show(false)

即使在使用文件中的停用词过滤输出的经典示例中,它们也会这样做:

val stopWords = stopWordsInput.flatMap(x => x.split(" ")).map(_.trim).collect.toSet

如果对工人来说太大,则广播。但我不确定 10 万是什么!!!

另一种方法是使用 Spark SQL,在使用 EXISTS 时依靠 Catalyst 优化 SQL:

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

val df1 = Seq("Rey", "John", "Donald", "Trump").toDF("Name")
val df2 = Seq("Rey", "Donald").toDF("Id") // This can be read from file and split etc.

// Optimizer converts to better physical plan for performance in general
df1.createOrReplaceTempView("searchlist") 
df2.createOrReplaceTempView("inlist")    
val df3 = spark.sql("""SELECT Name, 1 
                     FROM searchlist A
                    WHERE EXISTS (select B.Id from inlist B WHERE B.Id = A.Name )
                                   UNION
                   SELECT Name, 0 
                     FROM searchlist A
                    WHERE NOT EXISTS (select B.Id from inlist B WHERE B.Id = A.Name )
                """)
df3.show(false)

【讨论】:

  • @thebluephantom 我尝试了你的第一种方法,但我不明白一些事情:OP 说过如果没有匹配,他想要 1,但是如果有匹配,你的解决方案会提供 1,对吗?
  • 前阵子,今晚再看。
  • 你很可能是对的,可以互换。容易。
猜你喜欢
  • 2019-11-30
  • 2022-01-18
  • 2021-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-06
  • 1970-01-01
相关资源
最近更新 更多