Scala:如何将数据从一列与数据框中的其他列匹配

时间:2018-03-06 17:21:13

标签: scala apache-spark

我有以下数据,并希望将df1的ID列中的数据与df2匹配。

DF1:

ID    key
1     
2     
3
4
5

DF2:

first  second third  key
--------------------------
1       9       9    777
9       8       8    878
8       1      10    765
10      12      19   909
11      2       20   708

代码:

val finalDF = Df1.join(DF2.withColumnRenamed("key", "key2"), $"ID" === $"first" || $"ID" === $"second" || $"ID" === $"third","left").select($"ID", $"key2".as("key")).show(false)

val notMatchingDF = finalDF.filter($"key" === "")
val matchingDF = finalDF.except(notMatchingDF)
val columnsToCheck = DF2.columns.toSet - "key" toList

import org.apache.spark.sql.functions._
val tempSelectedDetailsDF = DF2.select(array(columnsToCheck.map(col): _*).as("array"), col("key").as("key2"))
val arrayContains = udf((array: collection.mutable.WrappedArray[String], value: String) => array.contains(value))
val finalDF = df1.join(tempSelectedDetailsDF, arrayContains($"array", $"ID"), "left")
  .select($"ID", $"key2".as("key"))
  .na.fill("")

我得到的输出如下,

ID    key
1     777
1     765
2     708     
3
4
5

但是我期待如下,这里的逻辑来自df1,我们有id列值1,而在df2中,值1匹配不止一次因此我得到了输出。但我不应该在第一次出现时匹配第二次匹配。

预期产出:

ID    key
1     777
2     708     
3
4
5

1 个答案:

答案 0 :(得分:1)

  
    

我不应该在第一次出现时匹配第二次匹配。

  

我建议你为df2创建一个增加的id,用于在与df1连接时识别匹配的顺序,以便稍后在第一场比赛中轻松过滤。为此,您可以从monotonically_increasing_id()

中受益
import org.apache.spark.sql.functions._
val finalDF = Df1.join(DF2.withColumnRenamed("key", "key2").withColumn("order", monotonically_increasing_id()), $"ID" === $"first" || $"ID" === $"second" || $"ID" === $"third","left").select($"ID", $"key2".as("key").cast(StringType), $"order")

然后您将数据框分成匹配和不匹配的数据框

val notMatchingDF = finalDF.filter($"key".isNull || $"key" === "")
val matchingDF = finalDF.except(notMatchingDF)

matchingDF之后,生成行号,每个窗口上的每一行按ID分组,并按上面标记的增加ID排序。然后过滤第一个匹配的行。然后合并非匹配数据框删除新创建的列填充所有空字符

import org.apache.spark.sql.expressions._
def windowSpec = Window.partitionBy("ID").orderBy("order")

matchingDF.withColumn("order", row_number().over(windowSpec))
  .filter($"order" === 1)
  .union(notMatchingDF)
  .drop("order")
  .na.fill("")

您应该满足您的要求

+---+---+
|ID |key|
+---+---+
|1  |777|
|2  |708|
|3  |   |
|4  |   |
|5  |   |
+---+---+