【问题标题】:Lucene scoring: get cosine similarity as scoresLucene 评分:获取余弦相似度作为分数
【发布时间】:2016-12-11 20:39:25
【问题描述】:

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

// 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 等。 有什么可能的方法来实现它?

【问题讨论】:

  • 需要注意的一点:相似度公式不再是默认值。从 6.0 开始,Lucene 默认使用BM25 实现。旧的默认设置仍然可用,请参阅ClassicSimilarity

标签: elasticsearch solr lucene full-text-search text-mining


【解决方案1】:

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

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

编写您的自定义类(您只需要在您的类中重写一个方法)。

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() 返回索引中的文档总数。
  • stats.getDocFreq() 返回出现在查询和文档中的术语的文档频率。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-12
    • 2016-02-01
    • 2017-02-27
    • 2010-12-23
    • 2011-01-01
    • 2017-12-12
    • 2013-05-24
    相关资源
    最近更新 更多