blob: 443531f2536a658c0d792334585aa13901bfe502 [file] [log] [blame]
package org.apache.lucene.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.
*/
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import org.apache.lucene.util.Bits;
/** Internal document-at-a-time scorers used to deal with stupid coord() computation */
class BooleanTopLevelScorers {
/**
* Used when there is more than one scorer in a query, but a segment
* only had one non-null scorer. This just wraps that scorer directly
* to factor in coord().
*/
static class BoostedScorer extends FilterScorer {
final float boost;
BoostedScorer(Scorer in, float boost) {
super(in);
this.boost = boost;
}
@Override
public float score() throws IOException {
return in.score() * boost;
}
@Override
public Collection<ChildScorer> getChildren() {
return Collections.singleton(new ChildScorer(in, "BOOSTED"));
}
}
/**
* Used when there is more than one scorer in a query, but a segment
* only had one non-null scorer.
*/
static class BoostedBulkScorer extends BulkScorer {
final BulkScorer in;
final float boost;
BoostedBulkScorer(BulkScorer scorer, float boost) {
this.in = scorer;
this.boost = boost;
}
@Override
public int score(LeafCollector collector, Bits acceptDocs, int min, int max) throws IOException {
final LeafCollector wrapped = new FilterLeafCollector(collector) {
@Override
public void setScorer(Scorer scorer) throws IOException {
super.setScorer(new BoostedScorer(scorer, boost));
}
};
return in.score(wrapped, acceptDocs, min, max);
}
@Override
public long cost() {
return in.cost();
}
}
/**
* Used when there are both mandatory and optional clauses, but minShouldMatch
* dictates that some of the optional clauses must match. The query is a conjunction,
* but must compute coord based on how many optional subscorers matched (freq).
*/
static class CoordinatingConjunctionScorer extends ConjunctionScorer {
private final float coords[];
private final int reqCount;
private final Scorer req;
private final Scorer opt;
CoordinatingConjunctionScorer(Weight weight, float coords[], Scorer req, int reqCount, Scorer opt) {
super(weight, Arrays.asList(req, opt), Arrays.asList(req, opt));
this.coords = coords;
this.req = req;
this.reqCount = reqCount;
this.opt = opt;
}
@Override
public float score() throws IOException {
return (req.score() + opt.score()) * coords[reqCount + opt.freq()];
}
}
/**
* Used when there are mandatory clauses with one optional clause: we compute
* coord based on whether the optional clause matched or not.
*/
static class ReqSingleOptScorer extends ReqOptSumScorer {
// coord factor if just the required part matches
private final float coordReq;
// coord factor if both required and optional part matches
private final float coordBoth;
public ReqSingleOptScorer(Scorer reqScorer, Scorer optScorer, float coordReq, float coordBoth) {
super(reqScorer, optScorer);
this.coordReq = coordReq;
this.coordBoth = coordBoth;
}
@Override
public float score() throws IOException {
int curDoc = reqScorer.docID();
float reqScore = reqScorer.score();
if (optScorer == null) {
return reqScore * coordReq;
}
int optScorerDoc = optScorer.docID();
if (optScorerDoc < curDoc && (optScorerDoc = optScorer.advance(curDoc)) == NO_MORE_DOCS) {
optScorer = null;
return reqScore * coordReq;
}
return optScorerDoc == curDoc ? (reqScore + optScorer.score()) * coordBoth : reqScore * coordReq;
}
}
/**
* Used when there are mandatory clauses with optional clauses: we compute
* coord based on how many optional subscorers matched (freq).
*/
static class ReqMultiOptScorer extends ReqOptSumScorer {
private final int requiredCount;
private final float coords[];
public ReqMultiOptScorer(Scorer reqScorer, Scorer optScorer, int requiredCount, float coords[]) {
super(reqScorer, optScorer);
this.requiredCount = requiredCount;
this.coords = coords;
}
@Override
public float score() throws IOException {
int curDoc = reqScorer.docID();
float reqScore = reqScorer.score();
if (optScorer == null) {
return reqScore * coords[requiredCount];
}
int optScorerDoc = optScorer.docID();
if (optScorerDoc < curDoc && (optScorerDoc = optScorer.advance(curDoc)) == NO_MORE_DOCS) {
optScorer = null;
return reqScore * coords[requiredCount];
}
return optScorerDoc == curDoc ? (reqScore + optScorer.score()) * coords[requiredCount + optScorer.freq()] : reqScore * coords[requiredCount];
}
}
}