需求描述:
我想添加一个可以改变文档打分的因素,以便可以灵活调整搜索结果。
注:在Lucene6.6 版本的上 Document.setBoost 方法已经被删除。
通过阅读 文档 和 Lucene原理和代码解析(这是早期版本的) 其中相关部分,
我尝试了调整 Similarity ,但发现其暴露的接口修改起来还是太复杂了,通读其中涉及的源码还要消耗大量的精力,所以最终放弃了这个方式。
最后选择了重写 TopDocsCollector 的方式,虽然目的是达到了,但是多了很多代码,变得很不优雅,不知道大家是怎么做的,希望可以分享一下。
我目前的实现思路:
构建索引时为每个文档增加一个打分因子的Field:
doc.add(new NumericDocValuesField("score", score));
搜索调用这个接口:
IndexSearcher.search(Query query, CollectorManager<C, T> collectorManager)
重写CollectorManager,在newCollector()方法返回重写TopDocsCollector,大概如下,实际还有很多多余的代码,都是复制IndexSearcher里面的实现。
private static class SimpleTopScoreDocCollector extends TopScoreDocCollector {
SimpleTopScoreDocCollector(int numHits) {
super(numHits);
}
@Override
public LeafCollector getLeafCollector(LeafReaderContext context)
throws IOException {
final int docBase = context.docBase;
return new ScorerLeafCollector() {
@Override
public void collect(int doc) throws IOException {
float score = scorer.score();
NumericDocValues scoreDocValues = context.reader().getNumericDocValues("score");
if(scoreDocValues != null){
long factor = scoreDocValues.get(doc); //其实就为了增加这一句,多了n多代码~
score = score * factor; //假设相乘
}
// This collector cannot handle these scores:
assert score != Float.NEGATIVE_INFINITY;
assert !Float.isNaN(score);
totalHits++;
if (score <= pqTop.score) {
// Since docs are returned in-order (i.e., increasing doc Id), a document
// with equal score to pqTop.score cannot compete since HitQueue favors
// documents with lower doc Ids. Therefore reject those docs too.
return;
}
pqTop.doc = doc + docBase;
pqTop.score = score;
pqTop = pq.updateTop();
}
};
}
}