PySpark中有无连接条件的交叉连接计数为何存在差异?
Spark交叉连接结果差异问题解答
代码示例与疑问
代码片段
from pyspark.sql.types import StringType dfj3 = spark.createDataFrame( ['a','b','b'], StringType() ) dfj4 = spark.createDataFrame( ['c','d','e'], StringType() ) dfj3.join(dfj4).count() # crossjoin, count = 9 dfj3.join(dfj4, dfj3.value==dfj4.value).count() # innerjoin, count = 0 dfj3.join(dfj4, dfj3.value==dfj4.value, 'cross').count() # crossjoin with condition, count = 0
用户疑问
为何第一种和第三种交叉连接的执行结果不同?
我原本预期:带连接条件的交叉连接与无连接条件的交叉连接结果应一致,因为两者都应执行两张表的全量记录连接。
核心原因
你对Spark中cross连接类型的参数逻辑理解有误,关键区别在于:
- 无参数的
dfj3.join(dfj4):这是Spark默认的隐式笛卡尔积,不做任何过滤,直接生成两张表的全量两两匹配记录(3×3=9条),所以计数为9。 - 指定
'cross'类型并传入条件的join:Spark的cross连接类型设计上并不支持传入连接条件参数。当你强行传入条件时,Spark会将该条件解析为内连接的匹配规则——先执行笛卡尔积,再用条件过滤结果。由于dfj3和dfj4的value没有任何匹配项,过滤后结果为空,计数为0。
简单说:
- 无参数
join()是纯粹的全量交叉连接,无过滤。 - 带条件的
'cross'连接本质是笛卡尔积+条件过滤,和普通内连接的执行逻辑一致。
正确实现带过滤的交叉连接
如果想实现「先做全量交叉连接,再过滤」的逻辑,应该使用crossJoin方法配合where条件,写法更清晰规范:
dfj3.crossJoin(dfj4).where(dfj3.value == dfj4.value).count()
这个写法的逻辑和你第三种写法的实际执行逻辑一致,但语义更明确,不会产生误解。
内容的提问来源于stack exchange,提问作者Karthick
相关产品推荐
相关产品推荐

