我有一个包含大约 200 个文档的数据库,这些文档是我提取的 ngram。我想在我的数据库中找到与查询文档最相似的文档。换句话说,我想在数据库中找到与查询文档共享最多 ngram 数的文档。现在,我可以逐一检查并进行比较,但这将花费 O(N) 时间,并且如果 N 很大,则成本很高。我想知道是否有任何有效的数据结构或方法可以进行有效的相似性搜索。谢谢
给定 ngram 搜索类似文档的最佳方法
您可以在文档上使用散列矢量化器。结果将是一个向量列表。然后以同样的方式向量化你的 ngram 并计算这个新向量在旧向量上的投影。这等效于索引上的数据库连接,但开销可能较小。
桌子
ngram
docID
PK(主键)ngram、docID
取决于数据库可能会有所变化,但这是针对 TSQL
x 是您要匹配的文档
select top(1) with ties *
from
( select tm.docID, count(*) as count
from table td
join table tm
on tm.docID <> td.docID
and tm.ngram = td.ngram
and td.docID = x
group by tm.docID
) tt
order by count desc
连接在索引 (PK) 上,因此速度非常快。我在几秒钟内对一百万个文档执行此操作(使用更高级的条件)。
这将有利于更大的文档,但这就是您所要求的。
问题似乎正在改变
declare table @query (varchar ngram);
insert into @query values ('ng1'), ('ng2'), ('ng3');
select top(10) with ties *
from
( select tm.docID, count(*) as count
from table td
join @query
on tm.ngram = @query.ngram
group by tm.docID
) tt
order by count desc
根据您的说明-
通过数据库,可以说有一个代表文档的 ngram 模型的巨大列表
您最好做一些更有条理的事情并将数据放入关系数据库中。这将使您能够更轻松、更快速地进行更详细的分析。
我猜当您说“ngram”时,您的意思是“1gram”。如果需要,您可以将分析扩展到包括 2 克、3 克等。
我会有一个看起来像这样的表结构 -
1 克
ID
值
Docs
ID
DocTitle
DocAuthor
等
Docs1Grams
1GramID
DocID
1GramCount
因此,在Docs1Grams表中的记录中,当 1GramID 指向 1gram“the”且 DocID 指向文档“War and Peace”时,1GramCount 将保存 1gram“the”在 War and Peace 中出现的次数。
如果“战争与和平”的 DocID 为 1,“指环王”的 DocID 为 2,那么要计算这两个文档的 1 克相似度得分,您将使用以下查询 -
Select count(*) from Docs1Grams D1, Docs1Grams D2
where D1.DocID = 1 and
D2.DocID = 2 and
D1.1GramID = D2.1GramID and
D1.1GramCount > 0 and
D2.1GramCount > 0
通过概括和扩展查询,这可以很容易地更改为自动选择最高分数/计数,将您选择的文档与所有其他文档进行比较。
通过修改/扩展D1.1GramCount > 0 and D2.1GramCount > 0
查询部分,您可以通过例如添加 2Grams、3Grams 等或修改简单匹配以根据每 ngram 的百分比匹配来轻松地使比较更加复杂。
因此,如果您的主题文档有 0.0009% 的 1 克是“the”,文档 1 有 0.001%,文档 2 有 0.0015%,那么文档 1 在“the”上的得分会更高,因为差异的模数(或您选择的任何其他度量)使用)更小。