PySpark按条件拆分DataFrame连接后Union如何去除空值行
方案可行性结论
拆分B表分别连接再合并的方案完全可行。当前结果出现大量空值行,本质是连接类型选择和后续过滤步骤缺失导致的,调整后即可得到符合预期的结果。
问题产生原因
现有写法的问题点非常明确:
- 与reds子表连接时使用了左连接,会保留A表的全部行,不满足red匹配规则的A行,对应B表侧的字段会全部为null
- 与blues子表连接时如果同样使用左连接,也会产生同理的null行
- 两个连接结果直接union时,没有剔除这些B侧字段全为null的无效行,最终就会出现8行数据里一半是空值的情况
正确实现方式
你可以根据业务场景选以下两种任意一种实现,都能得到预期结果:
方式1:两次连接均使用内连接,直接合并
由于red类型的匹配规则只会命中reds子表的数据、blue类型的匹配规则只会命中blues子表的数据,直接用内连接就只会返回匹配成功的行,从根源上避免null行产生:
# 先修正原拆分代码的语法错误,补全引号、明确子表字段引用 reds = B.filter(B.type == 'red') blues = B.filter(B.type == 'blue') # 按对应规则做内连接,仅保留匹配成功的行 a_reds = A.join(reds, A.id1 == reds.id2, 'inner') a_blues = A.join(blues, (A.id2 == blues.id1) & (A.id3 == blues.id2), 'inner') # 直接合并即可得到目标结果 result = a_reds.union(a_blues)
方式2:保留左连接逻辑,合并后过滤无效行
如果你后续需要保留未匹配的A表行做其他处理,不想改成内连接,可以在合并后加一层过滤,剔除B侧字段为空的无效行:
reds = B.filter(B.type == 'red') blues = B.filter(B.type == 'blue') # 保留原有左连接写法 a_reds = A.join(reds, A.id1 == reds.id2, 'left') a_blues = A.join(blues, (A.id2 == blues.id1) & (A.id3 == blues.id2), 'left') # 过滤掉B侧type为空的未匹配行 result = a_reds.union(a_blues).filter("type is not null")
注意:写连接条件时不要直接引用原B表的字段,要明确使用拆分后子表的别名(如
reds.id2、blues.id1),否则会触发字段找不到的报错。
两种方式最终返回的结果都和给出的预期结果完全一致,没有多余空值行。
内容的提问来源于stack exchange,提问作者Lidia
相关产品推荐
相关产品推荐

