Lucene得分:得分为余弦相似度

时间:2016-12-11 20:39:25

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

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

// 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]中的余弦相似性,而不是coord-factor,doc-len-norm等等。 有什么方法可以实现它?

1 个答案:

答案 0 :(得分:1)

如果您已经阅读了这个官方documentation,您会意识到score表达式中的其余条款非常重要,这使得评分过程更加合理和连贯。

但是如果你想仅使用Cosine Similaity实现评分过程,那么你可以编写自定义相似度类。我在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 dot产品来计算查询和文档之间的相似性。公式是,

enter image description here

这里需要提到的两件事是:

  • stats.getNumberOfDocuments()返回索引中的总数文档。
  • stats.getDocFreq()会返回查询和文档中出现的字词的文档频率。

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

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