2012-02-21 71 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来在分数中利用这些提升。