正如您提到的,不允许使用索引访问 spark 数据框。这是使用 scala spark dataframe 的一种解决方案:
var sets = List(Set(1, 5, 7, 4), Set(3, 5, 0), Set(10, 1, 5)).toDF("sets")
.withColumn("i",monotonically_increasing_id()) // to create indexes
val jaccardSimUDF = udf((set1: Seq[Int], set2: Seq[Int]) => set1.sum + set2.sum) // dummy function, replace it with your implementation of Jaccard similarity
val resDF = sets.crossJoin(sets.withColumnRenamed("sets", "sets2").withColumnRenamed("i", "j"))
.withColumn("jaccardSim", jaccardSimUDF($"sets", $"sets2"))
基本上,我们需要对您的数据框进行交叉连接以拥有所有组合。然后我们可以应用“用户定义函数”(UDF)来计算 Jaccard 相似度。请注意,我创建索引是为了方便。
现在,如果你真的想要一个矩阵,你需要重塑这个数据框,但这不是火花本质。
正如评论中指出的那样, jaccard 相似度函数是对称的,因此您可以过滤不必要的索引,如下所示:
val resDF = sets.crossJoin(sets.withColumnRenamed("sets", "sets2").withColumnRenamed("i", "j"))
.filter($"i" < $"j")
.withColumn("jaccardSim", jaccardSimUDF($"sets", $"sets2"))
它可能看起来很难看,因为它仍然涉及完整的交叉连接,但由于 spark 依赖于惰性计算和 Catalyst 优化器,因此在实践中它并不是真正的完整交叉连接。所以我认为没有更好的解决方案。