You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spark中如何合并两个DataFrame且不产生额外行?

解决Spark DataFrame过滤时保留列类型且不新增行的问题

看起来你想要的是保留所有原始的"S/N"行,仅对item为"a"的行保留原数据,其余行用0填充,同时保证"S/N"列是数值类型——而你之前用union导致重复行,是因为union本质是行拼接(类似SQL的UNION ALL),会把两个DataFrame的所有行都叠加起来,自然会产生额外行。

这里有两种更简洁的方案,完全不需要创建多个中间DataFrame:

方案一:直接用条件判断修改原DataFrame

这种方式最直接,先把"S/N"转成数值类型,再用when函数对item和value列做条件赋值:

import org.apache.spark.sql.functions.{col, lit, when}

// 初始化DataFrame时直接将"S/N"转为整数类型
val DF1 = Seq( ("1","a",2), ("2","a",3), ("3","b",3), ("4","b",4), ("5","a",2))
  .toDF("S/N","item", "value")
  .withColumn("S/N", col("S/N").cast("integer")) // 转为数值类型,保证类型保留

// 直接在原DF上做条件修改
val resultDF = DF1
  .withColumn("item", when(col("item") === "a", col("item")).otherwise(lit(0)))
  .withColumn("value", when(col("item") === "a", col("value")).otherwise(lit(0)))

resultDF.show()

输出结果:

+---+----+-----+
|S/N|item|value|
+---+----+-----+
|  1|   a|    2|
|  2|   a|    3|
|  3|   0|    0|
|  4|   0|    0|
|  5|   a|    2|
+---+----+-----+

方案二:用左外连接关联过滤后的DataFrame

如果你已经有了过滤后的DF2,可以通过左外连接基于"S/N"关联原始DF的所有行,再填充空值为0:

import org.apache.spark.sql.functions.{col, lit, when}

val DF1 = Seq( ("1","a",2), ("2","a",3), ("3","b",3), ("4","b",4), ("5","a",2))
  .toDF("S/N","item", "value")
  .withColumn("S/N", col("S/N").cast("integer"))

val DF2 = DF1.filter(col("item") === "a")

// 基于"S/N"左外连接,保留所有原始行
val resultDF = DF1.select("S/N")
  .join(DF2, Seq("S/N"), "left_outer")
  .withColumn("item", when(col("item").isNotNull, col("item")).otherwise(lit(0)))
  .withColumn("value", when(col("value").isNotNull, col("value")).otherwise(lit(0)))

resultDF.show()

这个方案也会得到和上面完全一致的结果,且不会产生任何重复行。

为什么你的union方案会产生额外行?

Spark的union方法默认等价于SQL的UNION ALL,它会直接把两个DataFrame的行全部拼接在一起,不会做任何去重或匹配。你的DF2有3行,DF3有5行,所以拼接后会得到8行,这显然不是你想要的“合并”效果——你需要的是基于"S/N"的行匹配,而不是行拼接,所以union并不适用这个场景。

内容的提问来源于stack exchange,提问作者user3782604

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:38:10