【问题标题】:Custom lucene scoring - Dot product between field boost and query boost自定义 lucene 评分 - 字段提升和查询提升之间的点积
【发布时间】:2012-03-11 22:02:47
【问题描述】:

我想使用具有以下评分逻辑的 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 的东西和 NORMS 没什么……
  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);
}

谢谢!

【问题讨论】:

    标签: java lucene similarity information-retrieval


    【解决方案1】:

    您可以解决以下问题:

    • 您没有在粘贴的代码的 sn-p 中设置自定义相似度,请参阅 IndexSearcher#setSimilarity

    • 当 freq 等于 0 时,Similarity 实现的 ''tf'' 方法应返回 0。

    此外,您应该小心索引时间的提升。由于它们是在单个字节上编码的,因此可能会有一些精度损失,请参阅In Lucene, why do my boosted and unboosted documents get the same score?

    索引时间提升的一种替代方法是在不同的数字字段中索引提升值,然后使用CustomScoreQueryfloat FieldCacheSource 在分数中利用这些提升。

    【讨论】:

      【解决方案2】:

      找到答案 - 效果很好!

      受 Lucene 邮件列表中的另一个线程(关于 CustomScoreQuery 的问题)的启发,我正在使用这个运行良好的解决方案(有一个缺点):
      我发现我的一些问题是由于我的假设是错误的:
      我确实有许多具有相同字段 ID 的字段/查询术语。

      这毁了我的方法,因为查询提升是聚合的,我的计算是错误的。

      我所做的是在索引过程中将字段值添加到字段 id(用“_”连接),并作为字段值使用所需的分数。

      在搜索时,我使用简单的 FieldScoreQuery(原样,无需修改)和复杂的字段 ID。

      在这里我仍然可以使用 setBoost 来设置分数,因为现在我的文件是独一无二的。

      从逻辑上讲,这是完美的 - 使用 Lucene 的点积。

      缺点 - 许多不同类型的字段。

      重要提示:
      由于我没有使用索引文档字段的规范,因为权重是字段的值,所以我现在使用以下方法对字段进行索引:

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

      并且内存使用恢复正常...
      太酷了!

      【讨论】:

        猜你喜欢
        • 2017-05-26
        • 1970-01-01
        • 2018-03-02
        • 2017-06-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-05
        • 1970-01-01
        相关资源
        最近更新 更多