【问题标题】:Lucene: Score calculation with a PrefixQueryLucene:使用 PrefixQuery 计算分数
【发布时间】:2010-06-17 10:02:13
【问题描述】:

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

 @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

【问题讨论】:

    标签: java lucene lucene.net


    【解决方案1】:

    默认情况下,PrefixQuery 会重写查询以使用 ConstantScoreQuery,它为每个匹配的文档提供 1.0 分。我认为这是为了让 PrefixQuery 更快。所以你的提升被忽略了。

    如果您希望提升在您的 PrefixQuery 中生效,您需要调用 setRewriteMethod(),在您的前缀查询实例上使用 SCORING_BOOLEAN_QUERY_REWRITE 常量。见http://lucene.apache.org/java/2_9_1/api/all/index.html

    对于调试,您可以使用 searcher.explain()。

    【讨论】:

    • 请注意,当在字段级别使用 setBoost 时,这似乎也适用。即 PrefixQuery 似乎会忽略字段提升,除非您按照此处所述更改重写方法。
    【解决方案2】:

    这是预期的行为。以下是Lucene创作者Doug Cutting的解释:

    PrefixQuery 等价于包含所有匹配项的查询 前缀,因此通常包含很多术语。有了这么大 查询,匹配的文档可能包含较少的查询词和 因此比赛较弱。

    阅读引用的the original post

    使用 Lucene,通常最好只使用分数作为一组文档中相关性的相对度量。分数的绝对值会根据很多因素而变化,因此不应按原样使用。

    更新
    Cuting 的解释是指旧版本的 Lucene。因此,bajafresh4life 的答案是正确的。

    【讨论】:

      【解决方案3】:

      更改重写方法

      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_REWRITE 时,DefaultSimilarity.QueryNorm 在它返回的值用于Weight.Normalize 时干扰了我的分数,它被调用Query.Weight.

      【讨论】:

        猜你喜欢
        • 2012-05-08
        • 1970-01-01
        • 2017-03-07
        • 2014-06-21
        • 1970-01-01
        • 2010-09-14
        • 2015-12-19
        • 1970-01-01
        • 2018-05-23
        相关资源
        最近更新 更多