【发布时间】:2012-01-13 03:46:40
【问题描述】:
在 lucene 中是否有内置算法来查找两个文档之间的相似性? 当我通过默认的相似性类时,它会在比较查询和文档后给出分数。
我已经对我的文档 a 进行了索引,使用了雪球分析器,下一步将是查找两个文档之间的相似性。
有人可以提出解决方案吗?
【问题讨论】:
标签: lucene similarity
在 lucene 中是否有内置算法来查找两个文档之间的相似性? 当我通过默认的相似性类时,它会在比较查询和文档后给出分数。
我已经对我的文档 a 进行了索引,使用了雪球分析器,下一步将是查找两个文档之间的相似性。
有人可以提出解决方案吗?
【问题讨论】:
标签: lucene similarity
似乎没有内置算法。我相信您可以通过以下三种方式:
a) 对其中一个文档运行 MoreLikeThis 查询。遍历结果,检查 doc id 并获得分数。也许不漂亮,您可能需要返回很多文件,以便您想要成为返回的文件之一。
b) 余弦相似度:Mikos 在他的评论中提供的链接中的答案解释了如何计算两个文档的余弦相似度。
c) 计算您自己的 Lucene 相似度分数。 Lucene 分数为余弦相似度增加了一些因素 (http://lucene.apache.org/core/4_2_0/core/org/apache/lucene/search/similarities/TFIDFSimilarity.html)。
你可以使用
DefaultSimilarity ds = new DefaultSimilarity();
SimScorer scorer = ds.simScorer(stats , arc);
scorer.score(otherDocId, freq);
例如可以通过
获取参数AtomicReaderContext arc = IndexReader.leaves().get(0);
SimWeight stats = ds.computeWeight(1, collectionStats, termStats);
stats.normalize(1, 1);
反过来,您可以使用 TermVector 获取两个文档中的第一个文档的术语统计信息,并使用 IndexReader 获取集合统计信息。要获取 freq 参数,请使用
DocsEnum docsEnum = MultiFields.getTermDocsEnum(reader, null, field, term);
,遍历文档,直到找到第一个文档的文档 ID,然后执行
freq = docsEnum.freq();
请注意,您需要为第一个文档中的每个术语(或您要考虑的每个术语)调用“scorer.score”,并对结果进行总结。
最后,要与“queryNorm”和“coord”参数相乘,可以使用
//sumWeights was computed while iterating over the first termvector
//in the main loop by summing up "stats.getValueForNormalization();"
float queryNorm = ds.queryNorm(sumWeights);
//thisTV and otherTV are termvectors for the two documents.
//overlap can be easily calculated
float coord = ds.coord(overlap, (int) Math.min(thisTV.size(), otherTV.size()));
return coord * queryNorm * score;
所以这是一种应该有效的方法。它并不优雅,并且由于难以获得术语频率(迭代每个术语的 DocsEnum),它也不是很有效。我仍然希望这对某人有所帮助:)
【讨论】: