2010-06-17 65 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使用。