我有大的postgresql数据库,包含文件。每个文档表示为表中的一行。当新文档添加到数据库时,我需要检查重复项。但我不能只使用select
来找到完全匹配。两个文档可能略有不同,仍然可以视为重复文件,例如,如果某些次要字段不同而所有其他字段相同。
我研究这个问题并找到解决这个问题的方法。可以为每个文档计算MinHash
签名并构造反向索引,以查询数据库中的类似文档。但我无法理解如何将MinHash
映射到关系数据库。
据我所知,MinHash
签名是N个哈希的列表,其中N是多个属性。相似度计算如下:
# Given 2 signatures Sa and Sb containing N hashes.
# Calculate number of equal hashes Neq.
number_of_equal_hashes = 0
for ix in range(0, N):
if Sa[ix] == Sb[ix]:
number_of_equal_hashes += 1
similarity = float(number_of_equal_hashes)/N
如果您已经有两个签名,这很简单,问题是在数据库中找到相似度小于或等于某个值的所有文档(带有相应的签名)。
例如,我可以创建包含多个列的表,如下所示:
| minhash0 | minhash1 | minhash3 | docid |
每个minhashX
列对应于文档属性之一的minhash,docid
是文档的标识符。
我可以这样查询类似的记录:
select * from invidx
where ((case when minhash0=minhash2search0 then 1 else 0 end) +
(case when minhash1=minhash2search1 then 1 else 0 end) +
(case when minhash2=minhash2search2 then 1 else 0 end))/N > THRESHOLD
其中minhash2searchX
是新文档的最小值,而THRESHOLD是最小的相似度。但这种方法需要全面扫描。有加速算法的方法吗?
答案 0 :(得分:2)
为了利用倒排索引的使用优势,我建议您使用全文搜索引擎,例如: Lucene或Solr(基于Lucene)
您可以构建“文档”(根据Lucene),其中包含与文档的MinHashes相关联的字段(db记录)。请注意,您也可以索引数字字段(您只需要在方案中描述字段类型)。此外,您必须存储每个文档的主键,以将Lucene“文档”映射到数据库中的记录。
索引整个文档集。
要查找与给定文档类似的文档 - 您必须为每个字段计算MinHashes,并为query文档计算similar Lucene:
field1:MinHash1 OR field2:MinHash2 OR ...
随着更多字段与文档匹配 - 它具有更高的排名。因此,您可以选择排名最高的文档,并做出决定 - 如果它们在您的情况下非常相似
此外,boosting字段可能对您有用
答案 1 :(得分:1)
您的哈希表应包含两列:
| minhash | docid |
应该在minhash上建立索引。
当新文档到达时,您依次搜索其每个散列,查询表以查找共享该散列的先前文档。您可以计算出这些先前文档共享的小抄总数,然后丢弃所有少于(例如)共享小抄的50%的小抄。这样可以有效地产生一组至少(估计)相似度为50%的所有文档。
最后,为新文档的每个哈希插入新行。
使用Lucene或Solr是一个糟糕的解决方案。这将需要更多的存储空间,实现起来会更加复杂,并且效率会大大降低。是的,您可以让Lucene为您的小错误建立索引,并按照stemm的建议运行查询。这将返回甚至共享一个minhash的每个文档,该哈希可能为数万或数十万,具体取决于您的数据大小。然后,您必须使用“相似性”功能将这些中的每一个分别与传入文档进行比较,这将非常慢。
Lucene确实提供了“ MoreLikeThis”功能来查找共享某些关键字的文档,但这会遗漏minhash方法可以找到的许多相似文档。