我构建了一个查询,它基本上是其他查询的加权和:
val query = new BooleanQuery
for ((subQuery, weight) <- ...) {
subQuery.setBoost(weight)
query.add(subQuery, BooleanClause.Occur.MUST)
}
当我查询索引时,我会找回总分数的文档。这很好,但我还需要知道每个子查询的子分数是多少。我怎么能得到那些?这就是我现在正在做的事情:
for (scoreDoc <- searcher.search(query, nHits).scoreDocs) {
val score = scoreDoc.score
val subScores = subQueries.map { subQuery =>
val weight = searcher.createNormalizedWeight(subQuery)
val scorer = weight.scorer(reader, true, true)
scorer.advance(scoreDoc.doc)
scorer.score
}
}
我认为这给了我正确的分数,但是当我知道它已经作为整体分数的一部分得分时,进展并重新评分该文档似乎是浪费。
是否有更有效的方法来获得这些子分数?
[我的代码在Scala中,但如果更容易,可以用Java回复。]
编辑:以下是遵循罗伯特·穆尔建议后的情况。
查询:
val query = new BooleanQuery
for ((subQuery, weight) <- ...) {
val weightedQuery = new BoostedQuery(subQuery, new ConstValueSource(weight))
query.add(weightedQuery, BooleanClause.Occur.MUST)
}
搜索:
val collector = new DocScoresCollector(nHits)
searcher.search(query, collector)
for (docScores <- collector.getDocSubScores) {
...
}
收藏家:
class DocScoresCollector(maxSize: Int) extends Collector {
var scorer: Scorer = null
var subScorers: Seq[Scorer] = null
val priorityQueue = new DocScoresPriorityQueue(maxSize)
override def setScorer(scorer: Scorer): Unit = {
this.scorer = scorer
// a little reflection hackery is required here because of a bug in
// BoostedQuery's scorer's getChildren method
// https://issues.apache.org/jira/browse/LUCENE-4261
this.subScorers = scorer.getChildren.asScala.map(childScorer =>
childScorer.child ...some hackery... ).toList
}
override def acceptsDocsOutOfOrder: Boolean = false
override def collect(doc: Int): Unit = {
this.scorer.advance(doc)
val score = this.scorer.score
val subScores = this.subScorers.map(_.score)
priorityQueue.insertWithOverflow(DocScores(doc, score, subScores))
}
override def setNextReader(context: AtomicReaderContext): Unit = {}
def getDocSubScores: Seq[DocScores] = {
val buffer = Buffer.empty[DocScores]
while (this.priorityQueue.size > 0) {
buffer += this.priorityQueue.pop
}
buffer
}
}
case class DocScores(doc: Int, score: Float, subScores: Seq[Float])
class DocScoresPriorityQueue(maxSize: Int) extends PriorityQueue[DocScores](maxSize) {
def lessThan(a: DocScores, b: DocScores) = a.score < b.score
}
答案 0 :(得分:1)
有一个得分手导航API:基本的想法是你写一个收藏家并在其setScorer方法中,通常你会保存对该得分手的引用以便稍后得分()每次击中,你现在可以走到那个树的那个记分员的分数等等。
请注意,记分员可以返回创建它们的权重,并将权重返回到查询。
使用所有这些,你可以在setScorer方法中隐藏对你关心的子核心的引用,例如:所有从TermQueries创建的。然后,当得分命中时,您可以调查收集器中这些节点的freq()和score()等内容。
在3.x系列中,这是一个限制为布尔关系的访问者API,在4.x系列中(截至目前只是一个alpha版本),你可以得到每个子核心的子+关系,所以它可以使用任意查询(包括您编写的自定义查询或其他任何查询)。
注意事项:
试验: