2010-06-17 115 views
8

我用PrefixQuery计算分数时遇到问题。为了改变每个文档的分数,当将文档添加到索引中时,我使用了setBoost来改变文档的提升。然后我创建PrefixQuery进行搜索,但结果并未根据提升进行更改。看来setBoost完全不适用于PrefixQuery。请检查下面我的代码:Lucene:使用前缀查询计算分数

@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 

回答

2

这是预期的行为。这里是Lucene的创作者道格切割的解释:

一个PrefixQuery等同于包含所有匹配 前缀的词语的查询,并因此通常包含了很多方面的。有了这样一个大的 查询,匹配文档可能会包含较少的查询条件和 匹配因此较弱。

阅读the original post报价取自哪里。

对于Lucene,通常只使用分数作为相关度量的一组文档中的相关度。分数的绝对值将根据如此多的因素而改变,以至于不应该按原样使用。

UPDATE
来自Cutting的解释指的是旧版本的Lucene。因此,bajafresh4life的答案是正确的。

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()。

+0

请注意,当在字段级别使用setBoost时,这似乎也适用。即PrefixQuery将会忽略字段提升,除非您按照此处所述更改rewrite方法。 – 2011-06-02 17:09:03

+0

这帮了我,请标记为答案。 – fommil 2013-07-24 12:52:24

0

更改写入方法

Bajafresh4life建议呼吁setRewriteMethod。但是,这不是你如何在Lucene.Net中改变这一点。以下是如何做到这一点在C#:

默认情况下,每个PrefixQuery是由QueryParserNewPrefixQuery方法,像这样返回:

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

可以使用的QueryParser.MultiTermRewriteMethodset属性实例化您的解析器后更改此,如下所示:

var parser = new QueryParser(Version.LUCENE_30, field, analyzer); 
parser.MultiTermRewriteMethod = MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE; 

请注意,这会改变其他查询的行为,而不仅仅是前缀查询。为了只影响前缀查询,您可以子类QueryParser并覆盖NewPrefixQuery,以便返回的PrefixQuery的构造函数使用您选择的重写方法。

其中写入方法使用

似乎并非有固定的对我来说,虽然。我实际上使用MultiTermQuery.CONSTANT_SCORE_BOOLEAN_QUERY_REWRITE有更好的运气。在这种方法的说明中,它说

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

但是,这可能是因为我还子类PrefixQuery和推翻ReWrite分配我想作为提升分数。

了相当数量的调试之后,我终于想通了,虽然我试图用SCORING_BOOLEAN_QUERY_REWRITEDefaultSimilarity.QueryNorm用我的成绩干扰,当它返回值Weight.Normalize,这就是所谓的Query.Weight使用。