Lucene评分问题

4

我在使用Lucene的评分功能时遇到了问题,但是我无法解决。到目前为止,我已经编写了以下代码来重现它。

package lucenebug;

import java.util.Arrays;
import java.util.List;

import org.apache.lucene.analysis.SimpleAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;

public class Test {
    private static final String TMP_LUCENEBUG_INDEX = "/tmp/lucenebug_index";

    public static void main(String[] args) throws Throwable {
        SimpleAnalyzer analyzer = new SimpleAnalyzer();
        IndexWriter w = new IndexWriter(TMP_LUCENEBUG_INDEX, analyzer, true);
        List<String> names = Arrays
                .asList(new String[] { "the rolling stones",
                        "rolling stones (karaoke)",
                        "the rolling stones tribute",
                        "rolling stones tribute band",
                        "karaoke - the rolling stones" });
        try {
            for (String name : names) {
                System.out.println("#name: " + name);
                Document doc = new Document();
                doc.add(new Field("name", name, Field.Store.YES,
                        Field.Index.TOKENIZED));
                w.addDocument(doc);
            }
            System.out.println("finished adding docs, total size: "
                    + w.docCount());

        } finally {
            w.close();
        }

        IndexSearcher s = new IndexSearcher(TMP_LUCENEBUG_INDEX);
        QueryParser p = new QueryParser("name", analyzer);
        Query q = p.parse("name:(rolling stones)");
        System.out.println("--------\nquery: " + q);

        TopDocs topdocs = s.search(q, null, 10);
        for (ScoreDoc sd : topdocs.scoreDocs) {
            System.out.println("" + sd.score + "\t"
                    + s.doc(sd.doc).getField("name").stringValue());
        }
    }
}

我运行它后得到的输出是:

finished adding docs, total size: 5
--------
query: name:rolling name:stones
0.578186    the rolling stones
0.578186    rolling stones (karaoke)
0.578186    the rolling stones tribute
0.578186    rolling stones tribute band
0.578186    karaoke - the rolling stones

我就是无法理解为什么“滚石乐队”和“滚石乐队致敬”具有相同的相关性。根据Lucene的文档,字段中的标记数量越多,规范化因子就应该越小,因此“滚石乐队致敬”应该比“滚石乐队”得分更低。
有什么想法吗?

你使用的是哪个Lucene版本(你可以链接2.4的API文档)?在Lucene 2.9中,默认情况下不返回分数,你需要提供一个TopFieldCollector:http://www.gossamer-threads.com/lists/lucene/java-user/86309 - digitalarbeiter
@gossamer:我已经对Lucene 2.3、2.4和2.9运行了相同的代码。结果都是一样的。 - Martin Blech
2个回答

5
长度归一化因子计算公式为1 / sqrt(numTerms)(您可以在DefaultSimilarity中查看)。
此结果不直接存储在索引中。该值乘以指定字段的增益值。最终结果然后编码为8位,如Similarity.encodeNorm()所述。这是一种有损编码,这意味着细节会丢失。
如果您想看到长度归一化的效果,请尝试创建以下句子的文档。
the rolling stones tribute a b c d e f g h i j k 

这将在长度标准化值上创建足够的差异,您可以看到。如果您的字段根据您使用的示例具有非常少的令牌,则可以根据自己的公式为文档/字段设置提升值,即短字段具有更高的提升值。或者,您可以创建自定义相似性并覆盖lengthNorm()方法。

没错,8位编码将boost*lengthNorm四舍五入导致了问题。在索引期间将字段boost设置为100对我来说是一个足够干净的解决方法。@Shashikant Kore 谢谢! - Martin Blech

0

我可以在Lucene 2.3.1上重现它,但不知道为什么会发生这种情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接