Lucene 评分:获得余弦相似度作为分数

Lucene scoring: get cosine similarity as scores

我正在尝试解决最近邻搜索问题。 这是我的代码:

// Indexing
val analyzer = new StandardAnalyzer()
val directory = new RAMDirectory()
val config = new IndexWriterConfig(analyzer)
val iwriter = new IndexWriter(directory, config)

val queryField = "fieldname"
stringData.foreach { str =>
  val doc = new Document()
  doc.add(new TextField(queryField, str, Field.Store.YES))
  iwriter.addDocument(doc)
}
iwriter.close()

// Searching
val ireader = DirectoryReader.open(directory)
val isearcher = new IndexSearcher(ireader)

val parser = new QueryParser(queryField, analyzer)
val query = parser.parse("Some text for testing")

val hits = isearcher.search(query, 10).scoreDocs

当我查看值命中时,我看到分数超过 1。

据我所知,lucene的评分公式是:

score(q,d) = coord-factor(q,d) · query-boost(q) · cosSim(q,d) · doc-len-norm(d) · doc-boost(d)

但我只想获得查询和文档之间范围 [0,1] 内的余弦相似度,而不是坐标因子、doc-len-norm 等。 实现它的可能方法是什么?

如果你看过这个官方 documentation,你会意识到 score 表达式中的其余术语很重要,可以使评分过程更加合乎逻辑和连贯。

但是,如果您想仅使用余弦相似度来实现评分过程,那么您可以编写自定义相似度 class。我在 class assignment 中使用了不同类型的相似度方法来进行文档检索。因此,简而言之,您可以编写自己的相似度方法并将其分配给 Lucene 的 index searcher。我在这里给出一个例子,你可以修改它来完成你想要的。

编写您的自定义 class(您只需要在 class 中覆盖一个方法)。

import org.apache.lucene.search.similarities.BasicStats;
import org.apache.lucene.search.similarities.SimilarityBase;

public class MySimilarity extends SimilarityBase {

    @Override
    protected float score(BasicStats stats, float termFreq, float docLength) {
        double tf = 1 + (Math.log(termFreq) / Math.log(2));
        double idf = Math.log((stats.getNumberOfDocuments() + 1) / stats.getDocFreq()) / Math.log(2);
        float dotProduct = (float) (tf * idf);
        return dotProduct;
    }

}

然后将您实现的方法分配给 index searcher 进行相关性计算,如下所示。

IndexReader reader = DirectoryReader.open(FSDirectory.open(new File(indexPath)));
IndexSearcher indexSearcher = new IndexSearcher(reader);
indexSearcher.setSimilarity(new MySimilarity());

在这里,我使用 tf-idf 点积来计算查询和文档之间的相似度。公式是,

这里需要说明两点:

  • stats.getNumberOfDocuments() returns 索引中的文档总数。
  • stats.getDocFreq() returns 一个词出现在查询和文档中的文档频率。

Lucene 现在将调用您已实现的 score() 方法来计算每个匹配项的相关性得分;在查询和文档中都出现的术语。

我知道这不是对您问题的直接回答,但您可以随意使用我上面提到的方法。我在家庭作业中实施了 6 种不同的评分技巧。希望对你也有帮助。