我有以下数据,并希望将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
答案 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 | |
+---+---+