排除对称结果的 PySpark 交叉连接

PySpark cross join excluding symmetric results

我有一个 Spark 数据框:

> df
+---+
| id|       
+---+
|  a|
+---+
|  b|
+---+
|  c|
+---+

我想获得 id 列的所有对,所以我需要交叉连接数据框本身。但我想排除对称结果(在我的例子中 a,b == b,a,等等)。

如果我应用 df.withColumnRenamed('id', 'id1').crossJoin(df.withColumnRenamed('id', 'id2')).show() 我得到以下输出:

+---+---+
|id1|id2|
+---+---+
|  a|  a|
|  a|  b|
|  a|  c|
|  b|  a|
|  b|  b|
|  b|  c|
|  c|  a|
|  c|  b|
|  c|  c|
+---+---+

但期望的输出是:

+---+---+
|id1|id2|
+---+---+
|  a|  a|
|  a|  b|
|  a|  c|
|  b|  b|
|  b|  c|
|  c|  c|
+---+---+

在 SQL 中,我可以使用这样的方法实现这样的结果:

select df1.*, df2.*
from df df1 join df df2
     on df1.id < df2.id

如何使用 PySpark 实现此功能?

您可以使用范围连接

df.withColumnRenamed('id', 'id1').createOrReplaceTempView("df1")

df.withColumnRenamed('id', 'id2').createOrReplaceTempView("df2")

spark.sql(
"""SELECT *
FROM df1, df2
WHERE df1.id1 = df2.id2
  OR df1.id1 < df2.id2""").show()

或者您可以按自己的方式进行交叉连接(这是一个非常昂贵的操作),从 id1 和 id2 创建数组并对其进行排序,对数组进行排序并使用它来删除重复项。我不建议交叉连接。

df.withColumnRenamed('id', 'id1').crossJoin(df.withColumnRenamed('id', 'id2')).withColumn('filter', array_sort(array('id1','id2'))).dropDuplicates(['filter']).drop('filter').show()

+---+---+
|id1|id2|
+---+---+
|  a|  a|
|  a|  b|
|  a|  c|
|  b|  b|
|  b|  c|
|  c|  c|
+---+---+