可同时选取左右DataFrame列的left-anti join替代方案咨询
解决Left-Anti Join同时保留左右表列的问题
首先纠正你现有代码的两处关键错误:
- 连接条件写法错误:
left_df.['col1_left_df']多了个多余的点,应该写成left_df['col1_left_df'] == right_df['col1_right_df'],或者用on参数简化写法。 - 过滤逻辑错误:Left-Anti要的是左表存在但右表无匹配的行,所以应该过滤右表的连接列为空,而不是左表的。你当前的
col('col1_left_df').isNull()会把左表本身就为空的行也筛选进来,不符合需求。
下面是几种可靠的实现方法:
方法一:修正左外连接+过滤(最直接高效)
先做左外连接,再过滤右表连接列为空的行,这样既保留Left-Anti的逻辑,又能同时获取左右表的列(右表列会显示为null,因为无匹配)。
from pyspark.sql import functions as F cols_to_keep = ['col1_left_df', 'col2_left_df', 'col3_left_df', 'col1_right_df', 'col2_right_df', 'col3_right_df'] non_matches = ( left_df.join( right_df, on=left_df['col1_left_df'] == right_df['col1_right_df'], how='left_outer' ) # 只保留右表连接列无匹配的行 .filter(F.col('col1_right_df').isNull()) .select(cols_to_keep) )
方法二:分步实现(逻辑更清晰)
先用Left-Anti Join拿到左表中无匹配的行,再和右表做左外连接,确保能保留你需要的右表列结构:
# 第一步:提取左表中没有匹配右表的行 left_only_rows = left_df.join(right_df, on='col1_left_df', how='left_anti') # 第二步:左连接右表,获取需要的右表列(此时右表列全为null) non_matches = left_only_rows.join( right_df.select(['col1_right_df', 'col2_right_df', 'col3_right_df']), on=left_only_rows['col1_left_df'] == right_df['col1_right_df'], how='left_outer' ).select(cols_to_keep)
方法三:使用exceptAll(适用于行级对比场景)
如果你的需求是找出左表中完全不存在于右表的行(基于指定键列),可以用exceptAll先筛选左表独有的行,再关联右表获取列:
# 先对齐右表的连接列名,和左表保持一致 right_aligned = right_df.withColumnRenamed('col1_right_df', 'col1_left_df') # 找出左表有但右表没有的行 left_only_rows = left_df.exceptAll(right_aligned.select(left_df.columns)) # 关联右表获取所需列 non_matches = left_only_rows.join( right_df, left_only_rows['col1_left_df'] == right_df['col1_right_df'], how='left_outer' ).select(cols_to_keep)
内容的提问来源于stack exchange,提问作者Vanessa_C
相关产品推荐
相关产品推荐

