2012-02-21 72 views
1

我想使用Lucene和以下評分邏輯: 當我索引我的文檔時,我想爲每個字段設置分數/權重。 當我查詢我的索引時,我想爲每個查詢項設置一個分數/權重。自定義lucene評分 - 字段提升和查詢提升之間的點積

我永遠不會索引或查詢具有相同字段的許多實例 - 在每個查詢(文檔)中將有0-1實例具有相同的字段名稱。 我的字段/查詢字詞未被分析 - 它們已經由一個標記構成。

我希望得分只是查詢字段與文檔字段之間的點積,如果它們具有相同的值。

例如:
格式是(字段名稱)(字段值)(場得分)
查詢:
1 AA 0.1
7 BB 0.2
8 CC 0.3

文獻1:
1 AA 0.2
2 DD 0.8
7 CC 0.999
10 FFF 0.1

文獻2:
7 BB 0.3
8 CC 0.5

分數應爲:
分數(Q,D1)= FIELD_1_SCORE_Q * FILED_1_SCORE_D1 = 0.1 * 0.2 = 0.02
分數(Q ,d2)= FIELD_7_SCORE_Q * FILED_7_SCORE_D2 + FIELD_8_SCORE_Q * FILED_8_SCORE_D2 =(0.2 * 0.3)+(0.3 * 0.5)

實現它的最佳方式是什麼?在準確性和性能方面(我不需要TF和IDF計算)。

我目前通過設置字段和查詢條件的提升來實現它。 後來我改寫了DefaultSimilarity類和索引/查詢之前將其設置爲默認:

public class MySimilarity extends DefaultSimilarity { 

    @Override 
    public float computeNorm(String field, FieldInvertState state) { 
     return state.getBoost(); 
    } 

    @Override 
    public float queryNorm(float sumOfSquaredWeights) { 
     return 1; 
    } 

    @Override 
    public float tf(float freq) { 
     return 1; 
    } 

    @Override 
    public float idf(int docFreq, int numDocs) { 
     return 1; 
    } 

    @Override 
    public float coord(int overlap, int maxOverlap) { 
     return 1; 
    } 

} 


而基於http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/scoring.html這應該工作。
問題:

  1. 演出:我計算所有的TF/IDF的東西和規範 什麼...
  2. 比分我從TopScoreDocCollector得到的是不 一樣我從解釋得到。

這裏是我的代碼部分:

indexSearcher = new IndexSearcher(IndexReader.open(directory, true)); 
TopScoreDocCollector collector = TopScoreDocCollector.create(iTopN, true); 
indexSearcher.search(query, collector); 
ScoreDoc[] hits = collector.topDocs().scoreDocs; 
for (int i = 0; i < hits.length; ++i) { 
    int docId = hits[i].doc; 
    Document d = indexSearcher.doc(docId); 
    double score = hits[i].score; 
    String id = d.get(FIELD_ID); 
    Explanation explanation = indexSearcher.explain(query, docId); 
} 

謝謝!

回答

0

找出答案 - 它工作得很好!

在Lucene的郵件列表中的另一個線程(約CustomScoreQuery問題)我使用這個解決方案這是工作真的很好(有一個缺點)的啓發:
我發現我的一些問題,是由於這樣的事實:我的假設是錯誤的:
我確實有許多字段/查詢條件與相同的字段ID。

這毀了我的方法,因爲查詢提升是聚合的,我的計算是錯誤的。

我所做的是在索引期間,我將字段值添加到字段ID(通過'_'連接在一起),並且作爲字段值使用了所需的分數。

在搜索的時候,我用複雜的字段ID使用簡單的FieldScoreQuery(原樣,不需要修改)。

在這裏,我仍然可以使用setBoost設置分數,因爲現在我的字段是唯一的。

邏輯明智,這是完美的 - 使用Lucene的點產品。

缺點 - 許多不同類型的領域。

重要:
因爲我沒有使用索引的文檔字段的規範,因爲重量是外地的,我現在使用索引字段中的值:

Field field = new Field(field_name, Float.toString(weight), Store.YES, Index.NOT_ANALYZED_NO_NORMS);<br> 

而且內存使用恢復正常...
太酷了!

0

有幾件事情,你可以修復:

  • 你不設置自定義的相似度在你粘貼代碼片段,看到IndexSearcher#setSimilarity

  • 的'TF'當freq等於0時,實現相似性的方法應返回0.

此外,您應該小心索引時間提升。由於它們編碼在單個字節上,因此可能會有一些精度損失,請參見In Lucene, why do my boosted and unboosted documents get the same score?

索引時間提升的一種替代方法可以是在不同的數字字段中索引提升值,然後使用CustomScoreQueryfloat FieldCacheSource來在分數中利用這些提升。