blob: ea4bc1d4403bc31b391d08eaef8755fd44083955 [file] [log] [blame]
using System;
namespace Lucene.Net.Search
{
/*
* 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.
*/
/// <summary>
/// The <see cref="Scorer"/> for <see cref="DisjunctionMaxQuery"/>. The union of all documents generated by the 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 <see cref="tieBreakerMultiplier"/> times the sum of the scores
/// for the other subqueries that generate the document.
/// </summary>
internal class DisjunctionMaxScorer : DisjunctionScorer
{
/// <summary>Multiplier applied to non-maximum-scoring subqueries for a document as they are summed into the result.</summary>
private readonly float tieBreakerMultiplier;
private int freq = -1;
/// <summary>Used when scoring currently matching doc.</summary>
private float scoreSum;
private float scoreMax;
/// <summary>
/// Creates a new instance of <see cref="DisjunctionMaxScorer"/>
/// </summary>
/// <param name="weight">
/// The <see cref="Weight"/> to be used. </param>
/// <param name="tieBreakerMultiplier">
/// Multiplier applied to non-maximum-scoring subqueries for a
/// document as they are summed into the result. </param>
/// <param name="subScorers">
/// The sub scorers this <see cref="Scorer"/> should iterate on </param>
public DisjunctionMaxScorer(Weight weight, float tieBreakerMultiplier, Scorer[] subScorers)
: base(weight, subScorers)
{
this.tieBreakerMultiplier = tieBreakerMultiplier;
}
/// <summary>
/// Determine the current document score. Initially invalid, until <see cref="DocIdSetIterator.NextDoc()"/> is called the first time. </summary>
/// <returns> The score of the current generated document </returns>
public override float GetScore()
{
return scoreMax + (scoreSum - scoreMax) * tieBreakerMultiplier;
}
protected override void AfterNext()
{
m_doc = m_subScorers[0].DocID;
if (m_doc != NO_MORE_DOCS)
{
scoreSum = scoreMax = m_subScorers[0].GetScore();
freq = 1;
ScoreAll(1);
ScoreAll(2);
}
}
/// <summary>
/// Recursively iterate all subScorers that generated last doc computing sum and max
/// </summary>
private void ScoreAll(int root)
{
if (root < m_numScorers && m_subScorers[root].DocID == m_doc)
{
float sub = m_subScorers[root].GetScore();
freq++;
scoreSum += sub;
scoreMax = Math.Max(scoreMax, sub);
ScoreAll((root << 1) + 1);
ScoreAll((root << 1) + 2);
}
}
public override int Freq => freq;
}
}