给文档添加权重 Lucene 8

Add weights to documents Lucene 8

我目前正在使用 Lucene 8 为大学开发一个小型搜索引擎。我之前已经构建过它,但是没有对文档应用任何权重。

我现在需要添加文档的 PageRanks 作为每个文档的权重,并且我已经计算了 PageRank 值。如何在 Lucene 8 中为 Document 对象( 不是查询词 )添加权重?我在网上查找了很多解决方案,但它们只适用于旧版本的 Lucene。 Example source

这是我的(更新)代码,它从 File 对象生成 Document 对象:

public static Document getDocument(File f) throws FileNotFoundException, IOException {
    Document d = new Document();

    //adding a field
    FieldType contentType = new FieldType();
    contentType.setStored(true);
    contentType.setTokenized(true);
    contentType.setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS);
    contentType.setStoreTermVectors(true);

    String fileContents = String.join(" ", Files.readAllLines(f.toPath(), StandardCharsets.UTF_8));
    d.add(new Field("content", fileContents, contentType));

    //adding other fields, then...

    //the boost coefficient (updated):
    double coef = 1.0 + ranks.get(path);
    d.add(new DoubleDocValuesField("boost", coef));

    return d;

}

我当前方法的问题是我需要一个 CustomScoreQuery 对象来搜索文档,但这在 Lucene 8 中不可用。另外,我现在不想降级到 Lucene 7毕竟我在 Lucene 8 中编写的所有代码。


编辑:

经过一些(冗长的)研究后,我在每个包含提升的文档中添加了一个 DoubleDocValuesField(请参阅上面更新的代码),并按照@EricLavault 的建议使用 FunctionScoreQuery 进行搜索。但是,现在我的所有文档都有一个准确的分数,无论查询如何! 我该如何解决这个问题?这是我的搜索功能:

public static TopDocs search(String query, IndexSearcher searcher, String outputFile) {
    try {
        Query q_temp = buildQuery(query); //the original query, was working fine alone

        Query q = new FunctionScoreQuery(q_temp, DoubleValuesSource.fromDoubleField("boost")); //the new query
        q = q.rewrite(DirectoryReader.open(bm25IndexDir));
        TopDocs results = searcher.search(q, 10);

        ScoreDoc[] filterScoreDosArray = results.scoreDocs;
        for (int i = 0; i < filterScoreDosArray.length; ++i) {
            int docId = filterScoreDosArray[i].doc;
            Document d = searcher.doc(docId);

            //here, when printing, I see that the document's score is the same as its "boost" value. WHY??
            System.out.println((i + 1) + ". " + d.get("path")+" Score: "+ filterScoreDosArray[i].score);
        }

        return results;
    }
    catch(Exception e) {
        e.printStackTrace();
        return null;
    }
}

//function that builds the query, working fine
public static Query buildQuery(String query) {
    try {
        PhraseQuery.Builder builder = new PhraseQuery.Builder();
        TokenStream tokenStream = new EnglishAnalyzer().tokenStream("content", query);
        tokenStream.reset();

        while (tokenStream.incrementToken()) {
          CharTermAttribute charTermAttribute = tokenStream.getAttribute(CharTermAttribute.class);
          builder.add(new Term("content", charTermAttribute.toString()));
        }

        tokenStream.end(); tokenStream.close();
        builder.setSlop(1000);
        PhraseQuery q = builder.build();

        return q;
    }
    catch(Exception e) {
        e.printStackTrace();
        return null;
    }
}

Lucene 6.5.0 开始:

Index-time boosts are deprecated. As a replacement, index-time scoring factors should be indexed into a doc value field and combined at query time using eg. FunctionScoreQuery. (Adrien Grand)

不使用索引时间提升的建议是将评分因素(即长度归一化因素)编码到文档值字段中。 (比照LUCENE-6819

关于我编辑的问题(提升值完全取代搜索分数而不是提升它),这是 documentation 关于 FunctionScoreQuery 的说法(强调我的):

A query that wraps another query, and uses a DoubleValuesSource to replace or modify the wrapped query's score.

那么,什么时候替换,什么时候修改?

事实证明,我使用的代码是用提升值完全替换分数:

Query q = new FunctionScoreQuery(q_temp, DoubleValuesSource.fromDoubleField("boost")); //the new query

我需要做的是使用函数 boostByValue,它修改搜索分数(通过将分数乘以提升值):

Query q = FunctionScoreQuery.boostByValue(q_temp, DoubleValuesSource.fromDoubleField("boost"));

现在可以了!感谢@EricLavault 的帮助!