如您链接的博客文章中所示,您可以使用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