我有两个数据集 dfA (5M) 和 dfB (6K)。我在 spark 2.2 上训练LSH :
val brp = new BucketedRandomProjectionLSH()
.setBucketLength(2.0)
.setNumHashTables(3)
.setInputCol("features")
.setOutputCol("hashes")
val brp_model = brp.fit(dfA)
val dfA_transformed = brp_model.transform(dfA)
val dfB_transformed = brp_model.transform(dfB)
我跟踪一对距离为 17.59 的记录:
val uidB = 601295446577L
val key_s = dfB_transformed
.filter(col("uid") === lit(uidB))
.select("features")
.as[String].collect()(0)
val key = Vectors.parse(key_s).asML
brp_model
.approxNearestNeighbors(dfA_transformed, key, 2, "distance")
.drop("features")
.show(5,false)
+-------------+-----------------------+------------------+
|uid |hashes |distance |
+-------------+-----------------------+------------------+
|1194000912899|[[0.0], [-1.0], [-1.0]]|17.592033410506907|
|163208761881 |[[0.0], [-1.0], [-1.0]]|19.912395647390348|
+-------------+-----------------------+------------------+
到目前为止,一切都很好。但是当我使用 approxSimilarityJoin 时,我没有得到我的 17.59 ,而是来自 A 的距离更大的其他人。
.approxSimilarityJoin(dfA_transformed, dfB_transformed, 25.0, "distance")
.persist(MEMORY_AND_DISK)
.filter(col("datasetB.uid") === lit(uidB))
+-------------+------------+------------------+
| uidA| uidB| distance|
+-------------+------------+------------------+
| 128849023798|601295446577|20.977834057053013|
|1005022360587|601295446577|21.919213729270727|
| 463856471960|601295446577|22.595725081515273|
| 670014905945|601295446577|23.396613579631136|
|1262720389581|601295446577| 24.03850371925476|
|1073741843710|601295446577|24.095447353196946|
+-------------+------------+------------------+
更准确地说,如果我使用persist,我永远不会得到那对,而没有persist ,我总是看到它存在。
每次运行生成的数据集都会显示大小大幅波动:
brp_model
.approxSimilarityJoin(dfA_transformed, dfB_transformed, 25.0, "distance")
.persist(MEMORY_AND_DISK)
.count()
// 20741736,18820380,20772153
brp_model
.approxSimilarityJoin(dfA_transformed, dfB_transformed, 25.0, "distance")
.count()
// 19371911,17323851,20074502
不过,我了解哈希冲突的随机性质:
- 在这里使用持久性有什么问题吗?
- 可以做些什么来提高approxSimilarityJoin的准确性?我看不到任何工具可以评估 BucketLength 的好坏。
- 如果我提前知道 A 和 B,我应该在 A 和 B 的联合上训练brp吗?
- 遍历 B 并按键查询每条记录是一种更稳定的方法吗?