Lucene:使用PrefixQuery进行分数计算

时间:2010-06-17 10:02:13

标签: java lucene lucene.net

我在使用PrefixQuery进行分数计算时遇到问题。要更改每个文档的分数,在将文档添加到索引中时,我已使用setBoost来更改文档的提升。然后我创建PrefixQuery进行搜索,但结果没有根据提升进行更改。似乎setBoost完全不适用于PrefixQuery。请检查下面的代码:

 @Test
 public void testNormsDocBoost() throws Exception {
    Directory dir = new RAMDirectory();
    IndexWriter writer = new IndexWriter(dir, new StandardAnalyzer(Version.LUCENE_CURRENT), true,
            IndexWriter.MaxFieldLength.LIMITED);
    Document doc1 = new Document();
    Field f1 = new Field("contents", "common1", Field.Store.YES, Field.Index.ANALYZED);
    doc1.add(f1);
    doc1.setBoost(100);
    writer.addDocument(doc1);
    Document doc2 = new Document();
    Field f2 = new Field("contents", "common2", Field.Store.YES, Field.Index.ANALYZED);
    doc2.add(f2);
    doc2.setBoost(200);
    writer.addDocument(doc2);
    Document doc3 = new Document();
    Field f3 = new Field("contents", "common3", Field.Store.YES, Field.Index.ANALYZED);
    doc3.add(f3);
    doc3.setBoost(300);
    writer.addDocument(doc3);
    writer.close();

    IndexReader reader = IndexReader.open(dir);
    IndexSearcher searcher = new IndexSearcher(reader);

    TopDocs docs = searcher.search(new PrefixQuery(new Term("contents", "common")), 10);
    for (ScoreDoc doc : docs.scoreDocs) {
        System.out.println("docid : " + doc.doc + " score : " + doc.score + " "
                + searcher.doc(doc.doc).get("contents"));
    }
} 

输出结果为:

 docid : 0 score : 1.0 common1
 docid : 1 score : 1.0 common2
 docid : 2 score : 1.0 common3

3 个答案:

答案 0 :(得分:11)

默认情况下,PrefixQuery会重写查询以使用ConstantScoreQuery,它会为每个匹配的文档提供1.0分。我认为这是为了让PrefixQuery更快。所以你的提升被忽略了。

如果希望提升在PrefixQuery中生效,则需要使用前缀查询实例上的SCORING_BOOLEAN_QUERY_REWRITE常量来调用setRewriteMethod()。见http://lucene.apache.org/java/2_9_1/api/all/index.html

对于调试,您可以使用searcher.explain()。

答案 1 :(得分:2)

这是预期的行为。以下是Lucene创作者Doug Cutting的解释:

  

PrefixQuery相当于包含与之匹配的所有术语的查询   前缀,因此通常包含很多术语。有这么大的   查询,匹配文档可能包含较少的查询术语和   因此比赛较弱。

阅读引用所在的the original post

对于Lucene,通常最好将分数用作一组文档中相关性的相对度量。分数的绝对值将根据许多因素而改变,不应该按原样使用。

<强>更新
Cutting的解释是指较旧版本的Lucene。因此bajafresh4life的答案是正确的。

答案 2 :(得分:0)

更改重写方法

Bajafresh4life建议拨打setRewriteMethod。但是,这不是你在Lucene.Net中改变它的方式。以下是如何在C#中执行此操作:

默认情况下,每个PrefixQuery都由NewPrefixQuery QueryParser方法返回,如下所示:

protected internal virtual Query NewPrefixQuery(Term prefix)
{
    return new PrefixQuery(prefix) { RewriteMethod = multiTermRewriteMethod };
}

您可以在使用set的{​​{1}}属性实例化解析器后更改此设置,如下所示:

QueryParser.MultiTermRewriteMethod

请注意,这也会改变其他查询的行为,而不仅仅是前缀查询。要仅影响前缀查询,您可以继承var parser = new QueryParser( Version.LUCENE_30, field, analyzer ); parser.MultiTermRewriteMethod = MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE; 并覆盖QueryParser,以便返回的NewPrefixQuery的构造函数使用您选择的重写方法。

使用哪种重写方法

但这似乎并没有为我修复它。实际上我使用PrefixQuery的运气更好。在此方法的描述中,它说

  

与SCORING_BOOLEAN_QUERY_REWRITE类似,但不计算分数。相反,每个匹配的文档都会得到一个等于查询提升的常数分数。

但这可能是因为我还将MultiTermQuery.CONSTANT_SCORE_BOOLEAN_QUERY_REWRITE子类化并覆盖PrefixQuery以指定我想要的分数作为提升。

经过大量的调试后,我最终发现,当我尝试使用ReWrite时,SCORING_BOOLEAN_QUERY_REWRITEDefaultSimilarity.QueryNorm中使用它返回的值时干扰了我的分数},在Weight.Normalize中调用。