/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.lucene.search;

import java.io.IOException;
import java.util.List;

import org.apache.lucene.util.MathUtil;

import static org.apache.lucene.search.DocIdSetIterator.NO_MORE_DOCS;

The Scorer for DisjunctionMaxQuery. The union of all documents generated by the subquery scorers is generated in document number order. The score for each document is the maximum of the scores computed by the subquery scorers that generate that document, plus tieBreakerMultiplier times the sum of the scores for the other subqueries that generate the document.
/** * The Scorer for DisjunctionMaxQuery. The union of all documents generated by the subquery scorers * is generated in document number order. The score for each document is the maximum of the scores computed * by the subquery scorers that generate that document, plus tieBreakerMultiplier times the sum of the scores * for the other subqueries that generate the document. */
final class DisjunctionMaxScorer extends DisjunctionScorer { private final List<Scorer> subScorers; /* Multiplier applied to non-maximum-scoring subqueries for a document as they are summed into the result. */ private final float tieBreakerMultiplier;
Creates a new instance of DisjunctionMaxScorer
Params:
  • weight – The Weight to be used.
  • tieBreakerMultiplier – Multiplier applied to non-maximum-scoring subqueries for a document as they are summed into the result.
  • subScorers – The sub scorers this Scorer should iterate on
/** * Creates a new instance of DisjunctionMaxScorer * * @param weight * The Weight to be used. * @param tieBreakerMultiplier * Multiplier applied to non-maximum-scoring subqueries for a * document as they are summed into the result. * @param subScorers * The sub scorers this Scorer should iterate on */
DisjunctionMaxScorer(Weight weight, float tieBreakerMultiplier, List<Scorer> subScorers, ScoreMode scoreMode) throws IOException { super(weight, subScorers, scoreMode); this.subScorers = subScorers; this.tieBreakerMultiplier = tieBreakerMultiplier; if (tieBreakerMultiplier < 0 || tieBreakerMultiplier > 1) { throw new IllegalArgumentException("tieBreakerMultiplier must be in [0, 1]"); } } @Override protected float score(DisiWrapper topList) throws IOException { float scoreMax = 0; double otherScoreSum = 0; for (DisiWrapper w = topList; w != null; w = w.next) { float subScore = w.scorer.score(); if (subScore >= scoreMax) { otherScoreSum += scoreMax; scoreMax = subScore; } else { otherScoreSum += subScore; } } return (float) (scoreMax + otherScoreSum * tieBreakerMultiplier); } @Override public int advanceShallow(int target) throws IOException { int upTo = NO_MORE_DOCS; for (Scorer scorer : subScorers) { if (scorer.docID() <= target) { upTo = Math.min(scorer.advanceShallow(target), upTo); } else if (scorer.docID() < NO_MORE_DOCS) { upTo = Math.min(scorer.docID()-1, upTo); } } return upTo; } @Override public float getMaxScore(int upTo) throws IOException { float scoreMax = 0; double otherScoreSum = 0; for (Scorer scorer : subScorers) { if (scorer.docID() <= upTo) { float subScore = scorer.getMaxScore(upTo); if (subScore >= scoreMax) { otherScoreSum += scoreMax; scoreMax = subScore; } else { otherScoreSum += subScore; } } } if (tieBreakerMultiplier == 0) { return scoreMax; } else { // The error of sums depends on the order in which values are summed up. In // order to avoid this issue, we compute an upper bound of the value that // the sum may take. If the max relative error is b, then it means that two // sums are always within 2*b of each other. otherScoreSum *= (1 + 2 * MathUtil.sumRelativeErrorBound(subScorers.size() - 1)); return (float) (scoreMax + otherScoreSum * tieBreakerMultiplier); } } @Override public void setMinCompetitiveScore(float minScore) { getBlockMaxApprox().setMinCompetitiveScore(minScore); } }