You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Spark DataFrame生成相似度矩阵的三角部分以降低计算量?

生成自笛卡尔积的下三角部分(最小计算量实现)

针对你想要避免生成完整自笛卡尔积、只保留对称矩阵下三角(不含对角线)的需求,这里有几个高效的Spark实现方案,能帮你大幅减少计算量:

方法1:添加唯一行标识后过滤

如果你的DataFrame没有天然的可比较唯一键,先给每条数据加一个唯一的行标识符,再通过过滤标识符的大小关系来保留下三角部分:

import org.apache.spark.sql.functions._

// 给原DataFrame添加唯一递增ID列
val dfWithId = df2.withColumn("row_id", monotonically_increasing_id())

// 自连接后过滤,只保留row_id小于重复表row_id的记录(下三角,不含对角线)
val lowerTriDF = dfWithId
  .crossJoin(dfWithId.as("dup_df"))
  .where(col("row_id") < col("dup_df.row_id"))
  // 可选:如果不需要重复的列,可以删除重复列或者重命名
  .drop(col("dup_df.row_id"))

monotonically_increasing_id()会生成全局唯一的递增ID,保证每行的标识不重复。如果你的数据有分区,也可以用row_number()配合分区键生成更紧凑的ID,但全局唯一的标识就足够满足需求。

方法2:利用现有唯一可比较列过滤

如果你的DataFrame已经有天然的唯一且可比较的列(比如用户ID、商品ID这类有序的唯一键),直接用这个列做过滤会更高效,省去添加额外列的开销:

// 假设df2有唯一可比较列user_id
val lowerTriDF = df2
  .crossJoin(df2.as("dup_df"))
  .where(col("user_id") < col("dup_df.user_id"))

这种方式不需要额外的计算来生成ID,直接利用现有业务列完成过滤,性能最优。

为什么这能减少计算量?

完整的自笛卡尔积会生成n²条记录(n是原DataFrame的行数),而通过上述过滤后,只会保留n(n-1)/2*条记录——相当于直接减少了近一半的计算量,完全避免了对称对的重复计算,正好符合你只需要下三角部分的需求。

如果之后需要补充对角线元素(值为1),可以单独生成对角线记录再union到结果中,但根据你的描述,这一步可以省略。


内容的提问来源于stack exchange,提问作者WestCoastProjects

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:49:33