我是Lucene的新手,对于任何不清楚的措辞,我深表歉意。我正在使用作者搜索引擎。搜索查询是作者姓名。默认搜索结果很好-它们返回最匹配的名称。但是,我们也希望按作者受欢迎程度对结果进行排名,这是默认相似度和代表其标题发行量的数值两者的混合。默认结果的问题在于,它会返回没有人感兴趣的作者,尽管我可以按发行量单独排名,但是就名字而言,最佳结果通常并不匹配。我一直在寻找解决方案。

这就是我建立索引的方式:

    IndexWriter writer = new IndexWriter(FSDirectory.open(Paths.get(INDEX_LOCATION)),
        new IndexWriterConfig(new StandardAnalyzer()));
    writer.deleteAll();
    for (Contributor contributor : contributors) {
        Document doc = new Document();
        doc.add(new TextField("name", contributor.getName(), Field.Store.YES));
        doc.add(new StoredField("contribId", contributor.getContribId()));
        doc.add(new NumericDocValuesField("sum", sum));
        writer.addDocument(doc);
    }
    writer.close();

名称是我们要搜索的字段,总和是我们要对搜索结果进行加权的字段(但仍要考虑作者姓名的最佳匹配)。我不确定在这种情况下将总和添加到文档中是否正确。我知道将需要进行一些实验,以找出如何最好地融合两个因素的权重,但是我的问题是我一开始不知道该怎么做。

我能够找到的任何示例都是Lucene 4之前的版本,或者似乎不起作用。我以为this是我想要的,但似乎没有用。帮助赞赏!

最佳答案

如您所链接的博客文章所示,您可以使用CustomScoreQuery;这会给您很大的灵活性,并在计分过程中发挥影响力,但这也有些过分。另一种可能性是使用FunctionScoreQuery;由于它们的行为不同,因此我将同时解释两者。

使用FunctionScoreQuery
FunctionScoreQuery可以基于字段修改分数。

假设您创建了自己,通常会执行如下搜索:

Query q = .... // pass the user input to the QueryParser or similar
TopDocs hits = searcher.search(query, 10); // Get 10 results

然后,您可以像下面这样修改查询:
Query q = .....

// Note that a Float field would work better.
DoubleValuesSource boostByField = DoubleValuesSource.fromLongField("sum");

// Create a query, based on the old query and the boost
FunctionScoreQuery modifiedQuery = new FunctionScoreQuery(q, boostByField);

// Search as usual
TopDocs hits = searcher.search(query, 10);

这将根据字段的值修改查询。但是,可悲的是,无法控制DoubleValuesSource的影响(除了在索引期间缩放值之外)-至少我不知道。

要获得更多控制,请考虑使用CustomScoreQuery

使用CustomScoreQuery

使用这种查询可以让您以自己喜欢的方式修改每个结果的分数。在这种情况下,我们将使用它根据索引中的字段更改分数。首先,您必须在建立索引期间存储您的值:
doc.add(new StoredField("sum", sum));

然后,我们将不得不创建自己的查询类:
private static class MyScoreQuery extends CustomScoreQuery {
    public MyScoreQuery(Query subQuery) {
        super(subQuery);
    }

    // The CustomScoreProvider is what actually alters the score
    private class MyScoreProvider extends CustomScoreProvider {

        private LeafReader reader;
        private Set<String> fieldsToLoad;

        public MyScoreProvider(LeafReaderContext context) {
            super(context);
            reader = context.reader();

            // We create a HashSet which contains the name of the field
            // which we need. This allows us to retrieve the document
            // with only this field loaded, which is a lot faster.
            fieldsToLoad = new HashSet<>();
            fieldsToLoad.add("sum");
        }

        @Override
        public float customScore(int doc_id, float currentScore, float valSrcScore) throws IOException {
            // Get the result document from the index
            Document doc = reader.document(doc_id, fieldsToLoad);

            // Get boost value from index
            IndexableField field = doc.getField("sum");
            Number number = field.numericValue();

            // This is just an example on how to alter the current score
            // based on the value of "sum". You will have to experiment
            // here.
            float influence = 0.01f;
            float boost = number.floatValue() * influence;

            // Return the new score for this result, based on the
            // original lucene score.
            return currentScore + boost;
        }
    }

    // Make sure that our CustomScoreProvider is being used.
    @Override
    public CustomScoreProvider getCustomScoreProvider(LeafReaderContext context) {
        return new MyScoreProvider(context);
    }
}

现在,您可以使用新的Query类来修改现有查询,类似于FunctionScoreQuery:
Query q = .....

// Create a query, based on the old query and the boost
MyScoreQuery modifiedQuery = new MyScoreQuery(q);

// Search as usual
TopDocs hits = searcher.search(query, 10);

结束语

使用CustomScoreQuery,您可以通过各种方式影响评分过程。但是请记住,每个搜索结果都会调用customScore方法-因此不要在其中执行任何昂贵的计算,因为这会严重减慢搜索过程。

我在这里创建了CustomScoreQuery的完整工作示例的小要点:https://gist.github.com/philippludwig/14e0d9b527a6522511ae79823adef73a

07-26 09:28