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

标签 pyspark apache-spark-sql cartesian-product cross-join

我有一个 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|
+---+---+

关于排除对称结果的 PySpark 交叉连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72426994/

相关文章:

python - Spark - 将 DataFrame 转换为 RowMatrix 以有效计算所有对的相似度

apache-spark - Apache Spark SQLContext 与 HiveContext 有什么区别?

algorithm - 什么是计算笛卡尔积的良好非递归算法?

scala - 仅使用 Spark-SQL API 时广播变量的使用

python - 列表字典的笛卡尔积作为项目

mysql - 需要使用多个表的条件来获取多个表的数据

python-2.7 - 如何正确使用 pyspark 向 kafka 代理发送数据?

python - 如何将列表保存到 spark 中的文件?

python - 对 Pyspark 数据帧进行分组和过滤

sql - Pyspark:根据多种条件过滤数据框