LUCENE-4607: add DISI/Spans.cost

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1456670 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Robert Muir 2013-03-14 20:48:23 +00:00
parent d7a71a3a29
commit 2c64eb9019
83 changed files with 696 additions and 302 deletions

View File

@ -76,6 +76,9 @@ New Features
* LUCENE-4827: Add additional ctor to PostingsHighlighter PassageScorer
to provide bm25 k1,b,avgdl parameters. (Robert Muir)
* LUCENE-4607: Add DocIDSetIterator.cost() and Spans.cost() for optimizing
scoring. (Simon Willnauer, Robert Muir)
Optimizations
* LUCENE-4819: Added Sorted[Set]DocValues.termsEnum(), and optimized the

View File

@ -1488,6 +1488,11 @@ public final class DirectPostingsFormat extends PostingsFormat {
}
return docID();
}
@Override
public long cost() {
return postings.length;
}
}
// Docs + freqs:
@ -1553,6 +1558,11 @@ public final class DirectPostingsFormat extends PostingsFormat {
}
return docID();
}
@Override
public long cost() {
return postings.length / 2;
}
}
// Docs + freqs + positions/offets:
@ -1634,6 +1644,12 @@ public final class DirectPostingsFormat extends PostingsFormat {
}
return docID();
}
@Override
public long cost() {
// TODO: could do a better estimate
return postings.length / 2;
}
}
private final static class LowFreqDocsAndPositionsEnum extends DocsAndPositionsEnum {
@ -1786,6 +1802,12 @@ public final class DirectPostingsFormat extends PostingsFormat {
return null;
}
}
@Override
public long cost() {
// TODO: could do a better estimate
return postings.length / 2;
}
}
// Docs + freqs:
@ -1959,6 +1981,11 @@ public final class DirectPostingsFormat extends PostingsFormat {
return docID = docIDs[upto];
}
}
@Override
public long cost() {
return docIDs.length;
}
}
// TODO: specialize offsets and not
@ -2192,5 +2219,10 @@ public final class DirectPostingsFormat extends PostingsFormat {
return payload;
}
}
@Override
public long cost() {
return docIDs.length;
}
}
}

View File

@ -431,6 +431,11 @@ public final class MemoryPostingsFormat extends PostingsFormat {
public int freq() {
return freq;
}
@Override
public long cost() {
return numDocs;
}
}
private final static class FSTDocsAndPositionsEnum extends DocsAndPositionsEnum {
@ -618,6 +623,11 @@ public final class MemoryPostingsFormat extends PostingsFormat {
public int freq() {
return freq;
}
@Override
public long cost() {
return numDocs;
}
}
private final static class FSTTermsEnum extends TermsEnum {

View File

@ -260,6 +260,7 @@ public class PulsingPostingsReader extends PostingsReaderBase {
private int accum;
private int freq;
private int payloadLength;
private int cost;
public PulsingDocsEnum(FieldInfo fieldInfo) {
indexOptions = fieldInfo.getIndexOptions();
@ -283,6 +284,7 @@ public class PulsingPostingsReader extends PostingsReaderBase {
docID = -1;
accum = 0;
freq = 1;
cost = termState.docFreq;
payloadLength = 0;
this.liveDocs = liveDocs;
return this;
@ -367,6 +369,11 @@ public class PulsingPostingsReader extends PostingsReaderBase {
}
return docID = NO_MORE_DOCS;
}
@Override
public long cost() {
return cost;
}
}
private static class PulsingDocsAndPositionsEnum extends DocsAndPositionsEnum {
@ -390,6 +397,7 @@ public class PulsingPostingsReader extends PostingsReaderBase {
private int offsetLength;
private boolean payloadRetrieved;
private int cost;
public PulsingDocsAndPositionsEnum(FieldInfo fieldInfo) {
indexOptions = fieldInfo.getIndexOptions();
@ -415,6 +423,7 @@ public class PulsingPostingsReader extends PostingsReaderBase {
posPending = 0;
docID = -1;
accum = 0;
cost = termState.docFreq;
startOffset = storeOffsets ? 0 : -1; // always return -1 if no offsets are stored
offsetLength = 0;
//System.out.println("PR d&p reset storesPayloads=" + storePayloads + " bytes=" + bytes.length + " this=" + this);
@ -551,6 +560,11 @@ public class PulsingPostingsReader extends PostingsReaderBase {
return null;
}
}
@Override
public long cost() {
return cost;
}
}
@Override

View File

@ -441,6 +441,11 @@ public class SepPostingsReader extends PostingsReaderBase {
return doc;
}
@Override
public long cost() {
return docFreq;
}
}
class SepDocsAndPositionsEnum extends DocsAndPositionsEnum {
@ -717,5 +722,10 @@ public class SepPostingsReader extends PostingsReaderBase {
pendingPayloadBytes = 0;
return payload;
}
@Override
public long cost() {
return docFreq;
}
}
}

View File

@ -199,7 +199,7 @@ class SimpleTextFieldsReader extends FieldsProducer {
} else {
docsEnum = new SimpleTextDocsEnum();
}
return docsEnum.reset(docsStart, liveDocs, indexOptions == IndexOptions.DOCS_ONLY);
return docsEnum.reset(docsStart, liveDocs, indexOptions == IndexOptions.DOCS_ONLY, docFreq);
}
@Override
@ -216,7 +216,7 @@ class SimpleTextFieldsReader extends FieldsProducer {
} else {
docsAndPositionsEnum = new SimpleTextDocsAndPositionsEnum();
}
return docsAndPositionsEnum.reset(docsStart, liveDocs, indexOptions);
return docsAndPositionsEnum.reset(docsStart, liveDocs, indexOptions, docFreq);
}
@Override
@ -234,6 +234,7 @@ class SimpleTextFieldsReader extends FieldsProducer {
private Bits liveDocs;
private final BytesRef scratch = new BytesRef(10);
private final CharsRef scratchUTF16 = new CharsRef(10);
private int cost;
public SimpleTextDocsEnum() {
this.inStart = SimpleTextFieldsReader.this.in;
@ -244,12 +245,13 @@ class SimpleTextFieldsReader extends FieldsProducer {
return in == inStart;
}
public SimpleTextDocsEnum reset(long fp, Bits liveDocs, boolean omitTF) throws IOException {
public SimpleTextDocsEnum reset(long fp, Bits liveDocs, boolean omitTF, int docFreq) throws IOException {
this.liveDocs = liveDocs;
in.seek(fp);
this.omitTF = omitTF;
docID = -1;
tf = 1;
cost = docFreq;
return this;
}
@ -316,6 +318,11 @@ class SimpleTextFieldsReader extends FieldsProducer {
while(nextDoc() < target);
return docID;
}
@Override
public long cost() {
return cost;
}
}
private class SimpleTextDocsAndPositionsEnum extends DocsAndPositionsEnum {
@ -334,6 +341,7 @@ class SimpleTextFieldsReader extends FieldsProducer {
private boolean readPositions;
private int startOffset;
private int endOffset;
private int cost;
public SimpleTextDocsAndPositionsEnum() {
this.inStart = SimpleTextFieldsReader.this.in;
@ -344,7 +352,7 @@ class SimpleTextFieldsReader extends FieldsProducer {
return in == inStart;
}
public SimpleTextDocsAndPositionsEnum reset(long fp, Bits liveDocs, IndexOptions indexOptions) {
public SimpleTextDocsAndPositionsEnum reset(long fp, Bits liveDocs, IndexOptions indexOptions, int docFreq) {
this.liveDocs = liveDocs;
nextDocStart = fp;
docID = -1;
@ -354,6 +362,7 @@ class SimpleTextFieldsReader extends FieldsProducer {
startOffset = -1;
endOffset = -1;
}
cost = docFreq;
return this;
}
@ -471,6 +480,11 @@ class SimpleTextFieldsReader extends FieldsProducer {
public BytesRef getPayload() {
return payload;
}
@Override
public long cost() {
return cost;
}
}
static class TermData {

View File

@ -444,6 +444,11 @@ public class SimpleTextTermVectorsReader extends TermVectorsReader {
this.doc = -1;
didNext = false;
}
@Override
public long cost() {
return 1;
}
}
private static class SimpleTVDocsAndPositionsEnum extends DocsAndPositionsEnum {
@ -535,5 +540,10 @@ public class SimpleTextTermVectorsReader extends TermVectorsReader {
return endOffsets[nextPos-1];
}
}
@Override
public long cost() {
return 1;
}
}
}

View File

@ -134,5 +134,14 @@ public final class MappingMultiDocsAndPositionsEnum extends DocsAndPositionsEnum
public BytesRef getPayload() throws IOException {
return current.getPayload();
}
@Override
public long cost() {
long cost = 0;
for (EnumWithSlice enumWithSlice : subs) {
cost += enumWithSlice.docsAndPositionsEnum.cost();
}
return cost;
}
}

View File

@ -114,5 +114,14 @@ public final class MappingMultiDocsEnum extends DocsEnum {
}
}
}
@Override
public long cost() {
long cost = 0;
for (EnumWithSlice enumWithSlice : subs) {
cost += enumWithSlice.docsEnum.cost();
}
return cost;
}
}

View File

@ -1037,6 +1037,10 @@ public final class CompressingTermVectorsReader extends TermVectorsReader implem
}
}
@Override
public long cost() {
return 1;
}
}
private static int sum(int[] arr) {

View File

@ -513,6 +513,11 @@ public class Lucene40PostingsReader extends PostingsReaderBase {
}
return scanTo(target);
}
@Override
public long cost() {
return limit;
}
}
private final class AllDocsSegmentDocsEnum extends SegmentDocsEnumBase {
@ -886,6 +891,11 @@ public class Lucene40PostingsReader extends PostingsReaderBase {
public BytesRef getPayload() throws IOException {
return null;
}
@Override
public long cost() {
return limit;
}
}
// Decodes docs & positions & (payloads and/or offsets)
@ -1179,5 +1189,10 @@ public class Lucene40PostingsReader extends PostingsReaderBase {
return null;
}
}
@Override
public long cost() {
return limit;
}
}
}

View File

@ -619,6 +619,11 @@ public class Lucene40TermVectorsReader extends TermVectorsReader implements Clos
this.doc = -1;
didNext = false;
}
@Override
public long cost() {
return 1;
}
}
private static class TVDocsAndPositionsEnum extends DocsAndPositionsEnum {
@ -726,6 +731,11 @@ public class Lucene40TermVectorsReader extends TermVectorsReader implements Clos
return endOffsets[nextPos-1];
}
}
@Override
public long cost() {
return 1;
}
}
@Override

View File

@ -599,6 +599,11 @@ public final class Lucene41PostingsReader extends PostingsReaderBase {
return nextDoc();
}
}
@Override
public long cost() {
return docFreq;
}
}
@ -1010,6 +1015,11 @@ public final class Lucene41PostingsReader extends PostingsReaderBase {
public BytesRef getPayload() {
return null;
}
@Override
public long cost() {
return docFreq;
}
}
// Also handles payloads + offsets
@ -1588,5 +1598,10 @@ public final class Lucene41PostingsReader extends PostingsReaderBase {
return payload;
}
}
@Override
public long cost() {
return docFreq;
}
}
}

View File

@ -251,6 +251,11 @@ public class FilterAtomicReader extends AtomicReader {
public AttributeSource attributes() {
return in.attributes();
}
@Override
public long cost() {
return in.cost();
}
}
/** Base class for filtering {@link DocsAndPositionsEnum} implementations. */
@ -310,6 +315,11 @@ public class FilterAtomicReader extends AtomicReader {
public AttributeSource attributes() {
return in.attributes();
}
@Override
public long cost() {
return in.cost();
}
}
/** The underlying AtomicReader. */

View File

@ -169,6 +169,15 @@ public final class MultiDocsAndPositionsEnum extends DocsAndPositionsEnum {
}
}
@Override
public long cost() {
long cost = 0;
for (int i = 0; i < numSubs; i++) {
cost += subs[i].docsAndPositionsEnum.cost();
}
return cost;
}
@Override
public String toString() {
return "MultiDocsAndPositionsEnum(" + Arrays.toString(getSubs()) + ")";

View File

@ -130,6 +130,15 @@ public final class MultiDocsEnum extends DocsEnum {
}
}
@Override
public long cost() {
long cost = 0;
for (int i = 0; i < numSubs; i++) {
cost += subs[i].docsEnum.cost();
}
return cost;
}
// TODO: implement bulk read more efficiently than super
/** Holds a {@link DocsEnum} along with the
* corresponding {@link ReaderSlice}. */

View File

@ -21,15 +21,10 @@ import java.io.IOException;
import java.util.*;
import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.index.DocsEnum;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.ConjunctionTermScorer.DocsAndFreqs;
import org.apache.lucene.search.TermQuery.TermWeight;
import org.apache.lucene.search.similarities.Similarity;
import org.apache.lucene.search.similarities.Similarity.ExactSimScorer;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.ToStringUtils;
@ -174,24 +169,18 @@ public class BooleanQuery extends Query implements Iterable<BooleanClause> {
protected ArrayList<Weight> weights;
protected int maxCoord; // num optional + num required
private final boolean disableCoord;
private final boolean termConjunction;
public BooleanWeight(IndexSearcher searcher, boolean disableCoord)
throws IOException {
this.similarity = searcher.getSimilarity();
this.disableCoord = disableCoord;
weights = new ArrayList<Weight>(clauses.size());
boolean termConjunction = clauses.isEmpty() || minNrShouldMatch != 0 ? false : true;
for (int i = 0 ; i < clauses.size(); i++) {
BooleanClause c = clauses.get(i);
Weight w = c.getQuery().createWeight(searcher);
if (!(c.isRequired() && (w instanceof TermWeight))) {
termConjunction = false;
}
weights.add(w);
if (!c.isProhibited()) maxCoord++;
}
this.termConjunction = termConjunction;
}
@Override
@ -310,10 +299,6 @@ public class BooleanQuery extends Query implements Iterable<BooleanClause> {
public Scorer scorer(AtomicReaderContext context, boolean scoreDocsInOrder,
boolean topScorer, Bits acceptDocs)
throws IOException {
if (termConjunction) {
// specialized scorer for term conjunctions
return createConjunctionTermScorer(context, acceptDocs);
}
List<Scorer> required = new ArrayList<Scorer>();
List<Scorer> prohibited = new ArrayList<Scorer>();
List<Scorer> optional = new ArrayList<Scorer>();
@ -356,32 +341,15 @@ public class BooleanQuery extends Query implements Iterable<BooleanClause> {
return null;
}
if (optional.size() == 0 && prohibited.size() == 0) {
float coord = disableCoord ? 1.0f : coord(required.size(), maxCoord);
return new ConjunctionScorer(this, required.toArray(new Scorer[required.size()]), coord);
}
// Return a BooleanScorer2
return new BooleanScorer2(this, disableCoord, minNrShouldMatch, required, prohibited, optional, maxCoord);
}
private Scorer createConjunctionTermScorer(AtomicReaderContext context, Bits acceptDocs)
throws IOException {
// TODO: fix scorer API to specify "needsScores" up
// front, so we can do match-only if caller doesn't
// needs scores
final DocsAndFreqs[] docsAndFreqs = new DocsAndFreqs[weights.size()];
for (int i = 0; i < docsAndFreqs.length; i++) {
final TermWeight weight = (TermWeight) weights.get(i);
final Scorer scorer = weight.scorer(context, true, false, acceptDocs);
if (scorer == null) {
return null;
} else {
assert scorer instanceof TermScorer;
docsAndFreqs[i] = new DocsAndFreqs((TermScorer) scorer);
}
}
return new ConjunctionTermScorer(this, disableCoord ? 1.0f : coord(
docsAndFreqs.length, docsAndFreqs.length), docsAndFreqs);
}
@Override
public boolean scoresDocsOutOfOrder() {
for (BooleanClause c : clauses) {

View File

@ -135,6 +135,9 @@ final class BooleanScorer extends Scorer {
@Override
public float score() { return (float)score; }
@Override
public long cost() { return 1; }
}
static final class Bucket {
@ -326,6 +329,11 @@ final class BooleanScorer extends Scorer {
throw new UnsupportedOperationException();
}
@Override
public long cost() {
return Integer.MAX_VALUE;
}
@Override
public void score(Collector collector) throws IOException {
score(collector, Integer.MAX_VALUE, -1);

View File

@ -147,6 +147,11 @@ class BooleanScorer2 extends Scorer {
public int advance(int target) throws IOException {
return scorer.advance(target);
}
@Override
public long cost() {
return scorer.cost();
}
}
private Scorer countingDisjunctionSumScorer(final List<Scorer> scorers,
@ -175,7 +180,7 @@ class BooleanScorer2 extends Scorer {
List<Scorer> requiredScorers) throws IOException {
// each scorer from the list counted as a single matcher
final int requiredNrMatchers = requiredScorers.size();
return new ConjunctionScorer(weight, requiredScorers) {
return new ConjunctionScorer(weight, requiredScorers.toArray(new Scorer[requiredScorers.size()])) {
private int lastScoredDoc = -1;
// Save the score of lastScoredDoc, so that we don't compute it more than
// once in score().
@ -200,7 +205,7 @@ class BooleanScorer2 extends Scorer {
private Scorer dualConjunctionSumScorer(boolean disableCoord,
Scorer req1, Scorer req2) throws IOException { // non counting.
return new ConjunctionScorer(weight, req1, req2);
return new ConjunctionScorer(weight, new Scorer[] { req1, req2 });
// All scorers match, so defaultSimilarity always has 1 as
// the coordination factor.
// Therefore the sum of the scores of two scorers
@ -322,6 +327,11 @@ class BooleanScorer2 extends Scorer {
return doc = countingSumScorer.advance(target);
}
@Override
public long cost() {
return countingSumScorer.cost();
}
@Override
public Collection<ChildScorer> getChildren() {
ArrayList<ChildScorer> children = new ArrayList<ChildScorer>();

View File

@ -89,6 +89,9 @@ public abstract class CachingCollector extends Collector {
@Override
public final int nextDoc() { throw new UnsupportedOperationException(); }
@Override
public long cost() { return 1; }
}
// A CachingCollector which caches scores

View File

@ -17,99 +17,76 @@ package org.apache.lucene.search;
* limitations under the License.
*/
import org.apache.lucene.util.ArrayUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import org.apache.lucene.util.ArrayUtil;
/** Scorer for conjunctions, sets of queries, all of which are required. */
class ConjunctionScorer extends Scorer {
protected int lastDoc = -1;
protected final DocsAndFreqs[] docsAndFreqs;
private final DocsAndFreqs lead;
private final float coord;
private final Scorer[] scorers;
private int lastDoc = -1;
public ConjunctionScorer(Weight weight, Collection<Scorer> scorers) throws IOException {
this(weight, scorers.toArray(new Scorer[scorers.size()]));
ConjunctionScorer(Weight weight, Scorer[] scorers) {
this(weight, scorers, 1f);
}
public ConjunctionScorer(Weight weight, Scorer... scorers) throws IOException {
ConjunctionScorer(Weight weight, Scorer[] scorers, float coord) {
super(weight);
this.scorers = scorers;
this.coord = coord;
this.docsAndFreqs = new DocsAndFreqs[scorers.length];
for (int i = 0; i < scorers.length; i++) {
if (scorers[i].nextDoc() == NO_MORE_DOCS) {
// If even one of the sub-scorers does not have any documents, this
// scorer should not attempt to do any more work.
lastDoc = NO_MORE_DOCS;
return;
docsAndFreqs[i] = new DocsAndFreqs(scorers[i]);
}
}
// Sort the array the first time...
// We don't need to sort the array in any future calls because we know
// it will already start off sorted (all scorers on same doc).
// Note that this comparator is not consistent with equals!
// Also we use mergeSort here to be stable (so order of Scoreres that
// match on first document keeps preserved):
ArrayUtil.mergeSort(scorers, new Comparator<Scorer>() { // sort the array
// Sort the array the first time to allow the least frequent DocsEnum to
// lead the matching.
ArrayUtil.mergeSort(docsAndFreqs, new Comparator<DocsAndFreqs>() {
@Override
public int compare(Scorer o1, Scorer o2) {
return o1.docID() - o2.docID();
public int compare(DocsAndFreqs o1, DocsAndFreqs o2) {
return Long.signum(o1.cost - o2.cost);
}
});
// NOTE: doNext() must be called before the re-sorting of the array later on.
// The reason is this: assume there are 5 scorers, whose first docs are 1,
// 2, 3, 5, 5 respectively. Sorting (above) leaves the array as is. Calling
// doNext() here advances all the first scorers to 5 (or a larger doc ID
// they all agree on).
// However, if we re-sort before doNext() is called, the order will be 5, 3,
// 2, 1, 5 and then doNext() will stop immediately, since the first scorer's
// docs equals the last one. So the invariant that after calling doNext()
// all scorers are on the same doc ID is broken.
if (doNext() == NO_MORE_DOCS) {
// The scorers did not agree on any document.
lastDoc = NO_MORE_DOCS;
return;
lead = docsAndFreqs[0]; // least frequent DocsEnum leads the intersection
}
// If first-time skip distance is any predictor of
// scorer sparseness, then we should always try to skip first on
// those scorers.
// Keep last scorer in it's last place (it will be the first
// to be skipped on), but reverse all of the others so that
// they will be skipped on in order of original high skip.
int end = scorers.length - 1;
int max = end >> 1;
for (int i = 0; i < max; i++) {
Scorer tmp = scorers[i];
int idx = end - i - 1;
scorers[i] = scorers[idx];
scorers[idx] = tmp;
}
}
private int doNext(int doc) throws IOException {
for(;;) {
// doc may already be NO_MORE_DOCS here, but we don't check explicitly
// since all scorers should advance to NO_MORE_DOCS, match, then
// return that value.
advanceHead: for(;;) {
for (int i = 1; i < docsAndFreqs.length; i++) {
// invariant: docsAndFreqs[i].doc <= doc at this point.
private int doNext() throws IOException {
int first = 0;
int doc = scorers[scorers.length - 1].docID();
Scorer firstScorer;
while ((firstScorer = scorers[first]).docID() < doc) {
doc = firstScorer.advance(doc);
first = first == scorers.length - 1 ? 0 : first + 1;
// docsAndFreqs[i].doc may already be equal to doc if we "broke advanceHead"
// on the previous iteration and the advance on the lead scorer exactly matched.
if (docsAndFreqs[i].doc < doc) {
docsAndFreqs[i].doc = docsAndFreqs[i].scorer.advance(doc);
if (docsAndFreqs[i].doc > doc) {
// DocsEnum beyond the current doc - break and advance lead to the new highest doc.
doc = docsAndFreqs[i].doc;
break advanceHead;
}
}
}
// success - all DocsEnums are on the same doc
return doc;
}
// advance head for next iteration
doc = lead.doc = lead.scorer.advance(doc);
}
}
@Override
public int advance(int target) throws IOException {
if (lastDoc == NO_MORE_DOCS) {
return lastDoc;
} else if (scorers[(scorers.length - 1)].docID() < target) {
scorers[(scorers.length - 1)].advance(target);
}
return lastDoc = doNext();
lead.doc = lead.scorer.advance(target);
return lastDoc = doNext(lead.doc);
}
@Override
@ -119,36 +96,47 @@ class ConjunctionScorer extends Scorer {
@Override
public int nextDoc() throws IOException {
if (lastDoc == NO_MORE_DOCS) {
return lastDoc;
} else if (lastDoc == -1) {
return lastDoc = scorers[scorers.length - 1].docID();
}
scorers[(scorers.length - 1)].nextDoc();
return lastDoc = doNext();
lead.doc = lead.scorer.nextDoc();
return lastDoc = doNext(lead.doc);
}
@Override
public float score() throws IOException {
// TODO: sum into a double and cast to float if we ever send required clauses to BS1
float sum = 0.0f;
for (int i = 0; i < scorers.length; i++) {
sum += scorers[i].score();
for (DocsAndFreqs docs : docsAndFreqs) {
sum += docs.scorer.score();
}
return sum;
return sum * coord;
}
@Override
public int freq() throws IOException {
return scorers.length;
public int freq() {
return docsAndFreqs.length;
}
@Override
public long cost() {
return lead.scorer.cost();
}
@Override
public Collection<ChildScorer> getChildren() {
ArrayList<ChildScorer> children = new ArrayList<ChildScorer>(scorers.length);
for (Scorer scorer : scorers) {
children.add(new ChildScorer(scorer, "MUST"));
ArrayList<ChildScorer> children = new ArrayList<ChildScorer>(docsAndFreqs.length);
for (DocsAndFreqs docs : docsAndFreqs) {
children.add(new ChildScorer(docs.scorer, "MUST"));
}
return children;
}
static final class DocsAndFreqs {
final long cost;
final Scorer scorer;
int doc = -1;
DocsAndFreqs(Scorer scorer) {
this.scorer = scorer;
this.cost = scorer.cost();
}
}
}

View File

@ -1,138 +0,0 @@
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.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import org.apache.lucene.index.DocsEnum;
import org.apache.lucene.util.ArrayUtil;
/** Scorer for conjunctions, sets of terms, all of which are required. */
class ConjunctionTermScorer extends Scorer {
protected final float coord;
protected int lastDoc = -1;
protected final DocsAndFreqs[] docsAndFreqs;
private final DocsAndFreqs lead;
ConjunctionTermScorer(Weight weight, float coord,
DocsAndFreqs[] docsAndFreqs) {
super(weight);
this.coord = coord;
this.docsAndFreqs = docsAndFreqs;
// Sort the array the first time to allow the least frequent DocsEnum to
// lead the matching.
ArrayUtil.mergeSort(docsAndFreqs, new Comparator<DocsAndFreqs>() {
@Override
public int compare(DocsAndFreqs o1, DocsAndFreqs o2) {
return o1.docFreq - o2.docFreq;
}
});
lead = docsAndFreqs[0]; // least frequent DocsEnum leads the intersection
}
private int doNext(int doc) throws IOException {
for(;;) {
// doc may already be NO_MORE_DOCS here, but we don't check explicitly
// since all scorers should advance to NO_MORE_DOCS, match, then
// return that value.
advanceHead: for(;;) {
for (int i = 1; i < docsAndFreqs.length; i++) {
// invariant: docsAndFreqs[i].doc <= doc at this point.
// docsAndFreqs[i].doc may already be equal to doc if we "broke advanceHead"
// on the previous iteration and the advance on the lead scorer exactly matched.
if (docsAndFreqs[i].doc < doc) {
docsAndFreqs[i].doc = docsAndFreqs[i].docs.advance(doc);
if (docsAndFreqs[i].doc > doc) {
// DocsEnum beyond the current doc - break and advance lead to the new highest doc.
doc = docsAndFreqs[i].doc;
break advanceHead;
}
}
}
// success - all DocsEnums are on the same doc
return doc;
}
// advance head for next iteration
doc = lead.doc = lead.docs.advance(doc);
}
}
@Override
public int advance(int target) throws IOException {
lead.doc = lead.docs.advance(target);
return lastDoc = doNext(lead.doc);
}
@Override
public int docID() {
return lastDoc;
}
@Override
public int nextDoc() throws IOException {
lead.doc = lead.docs.nextDoc();
return lastDoc = doNext(lead.doc);
}
@Override
public float score() throws IOException {
// TODO: sum into a double and cast to float if we ever send required clauses to BS1
float sum = 0.0f;
for (DocsAndFreqs docs : docsAndFreqs) {
sum += docs.scorer.score();
}
return sum * coord;
}
@Override
public int freq() {
return docsAndFreqs.length;
}
@Override
public Collection<ChildScorer> getChildren() {
ArrayList<ChildScorer> children = new ArrayList<ChildScorer>(docsAndFreqs.length);
for (DocsAndFreqs docs : docsAndFreqs) {
children.add(new ChildScorer(docs.scorer, "MUST"));
}
return children;
}
static final class DocsAndFreqs {
final DocsEnum docs;
final int docFreq;
final Scorer scorer;
int doc = -1;
DocsAndFreqs(TermScorer termScorer) {
this(termScorer, termScorer.getDocsEnum(), termScorer.getDocFreq());
}
DocsAndFreqs(Scorer scorer, DocsEnum docs, int docFreq) {
this.docs = docs;
this.docFreq = docFreq;
this.scorer = scorer;
}
}
}

View File

@ -206,6 +206,11 @@ public class ConstantScoreQuery extends Query {
return docIdSetIterator.advance(target);
}
@Override
public long cost() {
return docIdSetIterator.cost();
}
private Collector wrapCollector(final Collector collector) {
return new Collector() {
@Override

View File

@ -105,4 +105,13 @@ abstract class DisjunctionScorer extends Scorer {
}
return children;
}
@Override
public long cost() {
long sum = 0;
for (int i = 0; i < numScorers; i++) {
sum += subScorers[i].cost();
}
return sum;
}
}

View File

@ -36,6 +36,8 @@ public abstract class DocIdSet {
public int docID() { return NO_MORE_DOCS; }
@Override
public int nextDoc() { return NO_MORE_DOCS; }
@Override
public long cost() { return 0; }
};
@Override

View File

@ -93,4 +93,12 @@ public abstract class DocIdSetIterator {
*/
public abstract int advance(int target) throws IOException;
/**
* Returns the estimated cost of this {@link DocIdSetIterator}.
* <p>
* This is generally an upper bound of the number of documents this iterator
* might match, but may be a rough heuristic, hardcoded value, or otherwise
* completely inaccurate.
*/
public abstract long cost();
}

View File

@ -33,6 +33,7 @@ final class ExactPhraseScorer extends Scorer {
private final int[] gens = new int[CHUNK];
boolean noDocs;
private final long cost;
private final static class ChunkState {
final DocsAndPositionsEnum posEnum;
@ -66,6 +67,9 @@ final class ExactPhraseScorer extends Scorer {
endMinus1 = postings.length-1;
// min(cost)
cost = postings[0].postings.cost();
for(int i=0;i<postings.length;i++) {
// Coarse optimization: advance(target) is fairly
@ -315,4 +319,9 @@ final class ExactPhraseScorer extends Scorer {
return freq;
}
@Override
public long cost() {
return cost;
}
}

View File

@ -111,6 +111,11 @@ public abstract class FieldCacheDocIdSet extends DocIdSet {
}
return doc = NO_MORE_DOCS;
}
@Override
public long cost() {
return maxDoc;
}
};
} else if (acceptDocs instanceof FixedBitSet || acceptDocs instanceof OpenBitSet) {
// special case for FixedBitSet / OpenBitSet: use the iterator and filter it
@ -151,6 +156,11 @@ public abstract class FieldCacheDocIdSet extends DocIdSet {
}
return doc = NO_MORE_DOCS;
}
@Override
public long cost() {
return maxDoc;
}
};
}
}

View File

@ -82,4 +82,8 @@ public abstract class FilteredDocIdSetIterator extends DocIdSetIterator {
return doc;
}
@Override
public long cost() {
return _innerIter.cost();
}
}

View File

@ -210,6 +210,11 @@ public class FilteredQuery extends Query {
public Collection<ChildScorer> getChildren() {
return Collections.singleton(new ChildScorer(scorer, "FILTERED"));
}
@Override
public long cost() {
return scorer.cost();
}
}
/**
@ -304,6 +309,11 @@ public class FilteredQuery extends Query {
public final Collection<ChildScorer> getChildren() {
return Collections.singleton(new ChildScorer(scorer, "FILTERED"));
}
@Override
public long cost() {
return Math.min(primary.cost(), secondary.cost());
}
}
// TODO once we have way to figure out if we use RA or LeapFrog we can remove this scorer

View File

@ -781,6 +781,11 @@ public class IndexSearcher {
public float score() {
return score;
}
@Override
public long cost() {
return 1;
}
}
private final FakeScorer fakeScorer = new FakeScorer();

View File

@ -77,6 +77,11 @@ public class MatchAllDocsQuery extends Query {
doc = target-1;
return nextDoc();
}
@Override
public long cost() {
return maxDoc;
}
}
private class MatchAllDocsWeight extends Weight {

View File

@ -472,6 +472,7 @@ class UnionDocsAndPositionsEnum extends DocsAndPositionsEnum {
private int _freq;
private DocsQueue _queue;
private IntQueue _posList;
private long cost;
public UnionDocsAndPositionsEnum(Bits liveDocs, AtomicReaderContext context, Term[] terms, Map<Term,TermContext> termContexts, TermsEnum termsEnum) throws IOException {
List<DocsAndPositionsEnum> docsEnums = new LinkedList<DocsAndPositionsEnum>();
@ -488,6 +489,7 @@ class UnionDocsAndPositionsEnum extends DocsAndPositionsEnum {
// term does exist, but has no positions
throw new IllegalStateException("field \"" + term.field() + "\" was indexed without position data; cannot run PhraseQuery (term=" + term.text() + ")");
}
cost += postings.cost();
docsEnums.add(postings);
}
@ -570,4 +572,9 @@ class UnionDocsAndPositionsEnum extends DocsAndPositionsEnum {
public final int docID() {
return _doc;
}
@Override
public long cost() {
return cost;
}
}

View File

@ -128,4 +128,9 @@ class ReqExclScorer extends Scorer {
}
return doc = toNonExcluded();
}
@Override
public long cost() {
return reqScorer.cost();
}
}

View File

@ -99,5 +99,10 @@ class ReqOptSumScorer extends Scorer {
children.add(new ChildScorer(optScorer, "SHOULD"));
return children;
}
@Override
public long cost() {
return reqScorer.cost();
}
}

View File

@ -89,4 +89,9 @@ public class ScoreCachingWrappingScorer extends Scorer {
public Collection<ChildScorer> getChildren() {
return Collections.singleton(new ChildScorer(scorer, "CACHED"));
}
@Override
public long cost() {
return scorer.cost();
}
}

View File

@ -49,6 +49,7 @@ final class SloppyPhraseScorer extends Scorer {
private PhrasePositions[] rptStack; // temporary stack for switching colliding repeating pps
private int numMatches;
private final long cost;
SloppyPhraseScorer(Weight weight, PhraseQuery.PostingsAndFreq[] postings,
int slop, Similarity.SloppySimScorer docScorer) {
@ -57,6 +58,8 @@ final class SloppyPhraseScorer extends Scorer {
this.slop = slop;
this.numPostings = postings==null ? 0 : postings.length;
pq = new PhraseQueue(postings.length);
// min(cost)
cost = postings[0].postings.cost();
// convert tps to a list of phrase positions.
// note: phrase-position differs from term-position in that its position
// reflects the phrase offset: pp.pos = tp.pos - offset.
@ -589,6 +592,11 @@ final class SloppyPhraseScorer extends Scorer {
return max.doc;
}
@Override
public long cost() {
return cost;
}
@Override
public String toString() { return "scorer(" + weight + ")"; }
}

View File

@ -32,7 +32,6 @@ import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.search.similarities.Similarity.ExactSimScorer;
import org.apache.lucene.search.similarities.Similarity;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.ToStringUtils;
/** A Query that matches documents containing a term.
@ -85,7 +84,7 @@ public class TermQuery extends Query {
}
DocsEnum docs = termsEnum.docs(acceptDocs, null);
assert docs != null;
return new TermScorer(this, docs, similarity.exactSimScorer(stats, context), termsEnum.docFreq());
return new TermScorer(this, docs, similarity.exactSimScorer(stats, context));
}
/**

View File

@ -27,7 +27,6 @@ import org.apache.lucene.search.similarities.Similarity;
final class TermScorer extends Scorer {
private final DocsEnum docsEnum;
private final Similarity.ExactSimScorer docScorer;
private final int docFreq;
/**
* Construct a <code>TermScorer</code>.
@ -39,14 +38,11 @@ final class TermScorer extends Scorer {
* @param docScorer
* The </code>Similarity.ExactSimScorer</code> implementation
* to be used for score computations.
* @param docFreq
* per-segment docFreq of this term
*/
TermScorer(Weight weight, DocsEnum td, Similarity.ExactSimScorer docScorer, int docFreq) {
TermScorer(Weight weight, DocsEnum td, Similarity.ExactSimScorer docScorer) {
super(weight);
this.docScorer = docScorer;
this.docsEnum = td;
this.docFreq = docFreq;
}
@Override
@ -89,21 +85,12 @@ final class TermScorer extends Scorer {
return docsEnum.advance(target);
}
@Override
public long cost() {
return docsEnum.cost();
}
/** Returns a string representation of this <code>TermScorer</code>. */
@Override
public String toString() { return "scorer(" + weight + ")"; }
// TODO: benchmark if the specialized conjunction really benefits
// from this, or if instead its from sorting by docFreq, or both
DocsEnum getDocsEnum() {
return docsEnum;
}
// TODO: generalize something like this for scorers?
// even this is just an estimation...
int getDocFreq() {
return docFreq;
}
}

View File

@ -134,6 +134,15 @@ public class NearSpansOrdered extends Spans {
return matchPayload.isEmpty() == false;
}
@Override
public long cost() {
long minCost = Long.MAX_VALUE;
for (int i = 0; i < subSpans.length; i++) {
minCost = Math.min(minCost, subSpans[i].cost());
}
return minCost;
}
// inherit javadocs
@Override
public boolean next() throws IOException {

View File

@ -130,6 +130,11 @@ public class NearSpansUnordered extends Spans {
return spans.isPayloadAvailable();
}
@Override
public long cost() {
return spans.cost();
}
@Override
public String toString() { return spans.toString() + "#" + index; }
}
@ -268,6 +273,15 @@ public class NearSpansUnordered extends Spans {
return false;
}
@Override
public long cost() {
long minCost = Long.MAX_VALUE;
for (int i = 0; i < subSpans.length; i++) {
minCost = Math.min(minCost, subSpans[i].cost());
}
return minCost;
}
@Override
public String toString() {
return getClass().getName() + "("+query.toString()+")@"+

View File

@ -161,6 +161,11 @@ public class SpanNotQuery extends SpanQuery implements Cloneable {
return includeSpans.isPayloadAvailable();
}
@Override
public long cost() {
return includeSpans.cost();
}
@Override
public String toString() {
return "spans(" + SpanNotQuery.this.toString() + ")";

View File

@ -172,12 +172,14 @@ public class SpanOrQuery extends SpanQuery implements Cloneable {
return new Spans() {
private SpanQueue queue = null;
private long cost;
private boolean initSpanQueue(int target) throws IOException {
queue = new SpanQueue(clauses.size());
Iterator<SpanQuery> i = clauses.iterator();
while (i.hasNext()) {
Spans spans = i.next().getSpans(context, acceptDocs, termContexts);
cost += spans.cost();
if ( ((target == -1) && spans.next())
|| ((target != -1) && spans.skipTo(target))) {
queue.add(spans);
@ -259,6 +261,11 @@ public class SpanOrQuery extends SpanQuery implements Cloneable {
:(queue.size()>0?(doc()+":"+start()+"-"+end()):"END"));
}
@Override
public long cost() {
return cost;
}
};
}

View File

@ -180,6 +180,11 @@ public abstract class SpanPositionCheckQuery extends SpanQuery implements Clonea
return spans.isPayloadAvailable();
}
@Override
public long cost() {
return spans.cost();
}
@Override
public String toString() {
return "spans(" + SpanPositionCheckQuery.this.toString() + ")";

View File

@ -107,4 +107,9 @@ public class SpanScorer extends Scorer {
public float sloppyFreq() throws IOException {
return freq;
}
@Override
public long cost() {
return spans.cost();
}
}

View File

@ -84,4 +84,12 @@ public abstract class Spans {
*/
public abstract boolean isPayloadAvailable() throws IOException;
/**
* Returns the estimated cost of this spans.
* <p>
* This is generally an upper bound of the number of documents this iterator
* might match, but may be a rough heuristic, hardcoded value, or otherwise
* completely inaccurate.
*/
public abstract long cost();
}

View File

@ -99,6 +99,11 @@ public class TermSpans extends Spans {
return position + 1;
}
@Override
public long cost() {
return postings.cost();
}
// TODO: Remove warning after API has been finalized
@Override
public Collection<byte[]> getPayload() throws IOException {
@ -166,6 +171,11 @@ public class TermSpans extends Spans {
public boolean isPayloadAvailable() {
return false;
}
@Override
public long cost() {
return 0;
}
}
public static final TermSpans EMPTY_TERM_SPANS = new EmptyTermSpans();

View File

@ -95,5 +95,11 @@ public class DocIdBitSet extends DocIdSet implements Bits {
docId = d == -1 ? NO_MORE_DOCS : d;
return docId;
}
@Override
public long cost() {
// upper bound
return bitSet.length();
}
}
}

View File

@ -190,4 +190,8 @@ public class OpenBitSetIterator extends DocIdSetIterator {
return curDocId;
}
@Override
public long cost() {
return words / 64;
}
}

View File

@ -88,6 +88,11 @@ final class JustCompileSearch {
public int advance(int target) {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
@Override
public long cost() {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
}
static final class JustCompileExtendedFieldCacheLongParser implements FieldCache.LongParser {
@ -200,6 +205,10 @@ final class JustCompileSearch {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
@Override
public long cost() {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
}
static final class JustCompileQuery extends Query {
@ -246,6 +255,11 @@ final class JustCompileSearch {
public int advance(int target) {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
@Override
public long cost() {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
}
static final class JustCompileSimilarity extends Similarity {

View File

@ -92,6 +92,10 @@ public class TestBooleanScorer extends LuceneTestCase
return doc = target <= 3000 ? 3000 : NO_MORE_DOCS;
}
@Override
public long cost() {
return 1;
}
}};
BooleanScorer bs = new BooleanScorer(weight, false, 1, Arrays.asList(scorers), null, scorers.length);

View File

@ -47,6 +47,10 @@ public class TestCachingCollector extends LuceneTestCase {
@Override
public int advance(int target) throws IOException { return 0; }
@Override
public long cost() {
return 1;
}
}
private static class NoOpCollector extends Collector {

View File

@ -59,6 +59,11 @@ public class TestDocIdSet extends LuceneTestCase {
while (nextDoc() < target) {}
return docid;
}
@Override
public long cost() {
return 1;
}
};
}
};

View File

@ -536,6 +536,11 @@ public class TestFilteredQuery extends LuceneTestCase {
advanceCalled = true;
return termDocsEnum.advance(target);
}
@Override
public long cost() {
return termDocsEnum.cost();
}
};
}

View File

@ -50,6 +50,11 @@ public class TestPositiveScoresOnlyCollector extends LuceneTestCase {
idx = target;
return idx < scores.length ? idx : NO_MORE_DOCS;
}
@Override
public long cost() {
return scores.length;
}
}
// The scores must have positive as well as negative values

View File

@ -59,6 +59,10 @@ public class TestScoreCachingWrappingScorer extends LuceneTestCase {
return doc < scores.length ? doc : NO_MORE_DOCS;
}
@Override
public long cost() {
return scores.length;
}
}
private static final class ScoreCachingCollector extends Collector {

View File

@ -76,6 +76,10 @@ final class JustCompileSearchSpans {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
@Override
public long cost() {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
}
static final class JustCompileSpanQuery extends SpanQuery {
@ -134,6 +138,11 @@ final class JustCompileSearchSpans {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
@Override
public long cost() {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
}
static final class JustCompileSpanScorer extends SpanScorer {

View File

@ -167,4 +167,9 @@ public class MultiSpansWrapper extends Spans { // can't be package private due t
return current.isPayloadAvailable();
}
@Override
public long cost() {
return Integer.MAX_VALUE; // just for tests
}
}

View File

@ -614,6 +614,11 @@ class DrillSidewaysScorer extends Scorer {
throw new UnsupportedOperationException();
}
@Override
public long cost() {
return baseScorer.cost();
}
@Override
public Collection<ChildScorer> getChildren() {
return Collections.singletonList(new ChildScorer(baseScorer, "MUST"));

View File

@ -152,6 +152,11 @@ public class MatchingDocsAsScoredDocIDs implements ScoredDocIDs {
return doc + current.context.docBase;
}
@Override
public long cost() {
return size;
}
@Override
public int advance(int target) throws IOException {
throw new UnsupportedOperationException("not supported");

View File

@ -162,6 +162,10 @@ public class ScoredDocIdsUtils {
return docids[next];
}
@Override
public long cost() {
return size;
}
};
}
};
@ -298,6 +302,10 @@ public class ScoredDocIdsUtils {
return ++next < maxDoc ? next : NO_MORE_DOCS;
}
@Override
public long cost() {
return maxDoc;
}
};
}
};
@ -394,6 +402,10 @@ public class ScoredDocIdsUtils {
return next < maxDoc ? next : NO_MORE_DOCS;
}
@Override
public long cost() {
return maxDoc;
}
};
}
};

View File

@ -117,6 +117,11 @@ public class BlockGroupingCollector extends Collector {
public int nextDoc() {
throw new UnsupportedOperationException();
}
@Override
public long cost() {
return 1;
}
}
private static final class OneGroup {

View File

@ -497,6 +497,9 @@ public final class PostingsHighlighter {
@Override
public int advance(int target) throws IOException { return NO_MORE_DOCS; }
@Override
public long cost() { return 0; }
};
/**

View File

@ -161,17 +161,20 @@ class TermsIncludingScoreQuery extends Query {
return null;
}
// what is the runtime...seems ok?
final long cost = context.reader().maxDoc() * terms.size();
segmentTermsEnum = terms.iterator(segmentTermsEnum);
if (scoreDocsInOrder) {
if (multipleValuesPerDocument) {
return new MVInOrderScorer(this, acceptDocs, segmentTermsEnum, context.reader().maxDoc());
return new MVInOrderScorer(this, acceptDocs, segmentTermsEnum, context.reader().maxDoc(), cost);
} else {
return new SVInOrderScorer(this, acceptDocs, segmentTermsEnum, context.reader().maxDoc());
return new SVInOrderScorer(this, acceptDocs, segmentTermsEnum, context.reader().maxDoc(), cost);
}
} else if (multipleValuesPerDocument) {
return new MVInnerScorer(this, acceptDocs, segmentTermsEnum, context.reader().maxDoc());
return new MVInnerScorer(this, acceptDocs, segmentTermsEnum, context.reader().maxDoc(), cost);
} else {
return new SVInnerScorer(this, acceptDocs, segmentTermsEnum);
return new SVInnerScorer(this, acceptDocs, segmentTermsEnum, cost);
}
}
};
@ -183,16 +186,18 @@ class TermsIncludingScoreQuery extends Query {
final BytesRef spare = new BytesRef();
final Bits acceptDocs;
final TermsEnum termsEnum;
final long cost;
int upto;
DocsEnum docsEnum;
DocsEnum reuse;
int scoreUpto;
SVInnerScorer(Weight weight, Bits acceptDocs, TermsEnum termsEnum) {
SVInnerScorer(Weight weight, Bits acceptDocs, TermsEnum termsEnum, long cost) {
super(weight);
this.acceptDocs = acceptDocs;
this.termsEnum = termsEnum;
this.cost = cost;
}
@Override
@ -261,6 +266,11 @@ class TermsIncludingScoreQuery extends Query {
public int freq() {
return 1;
}
@Override
public long cost() {
return cost;
}
}
// This impl that tracks whether a docid has already been emitted. This check makes sure that docs aren't emitted
@ -270,8 +280,8 @@ class TermsIncludingScoreQuery extends Query {
final FixedBitSet alreadyEmittedDocs;
MVInnerScorer(Weight weight, Bits acceptDocs, TermsEnum termsEnum, int maxDoc) {
super(weight, acceptDocs, termsEnum);
MVInnerScorer(Weight weight, Bits acceptDocs, TermsEnum termsEnum, int maxDoc, long cost) {
super(weight, acceptDocs, termsEnum, cost);
alreadyEmittedDocs = new FixedBitSet(maxDoc);
}
@ -326,15 +336,17 @@ class TermsIncludingScoreQuery extends Query {
final DocIdSetIterator matchingDocsIterator;
final float[] scores;
final long cost;
int currentDoc = -1;
SVInOrderScorer(Weight weight, Bits acceptDocs, TermsEnum termsEnum, int maxDoc) throws IOException {
SVInOrderScorer(Weight weight, Bits acceptDocs, TermsEnum termsEnum, int maxDoc, long cost) throws IOException {
super(weight);
FixedBitSet matchingDocs = new FixedBitSet(maxDoc);
this.scores = new float[maxDoc];
fillDocsAndScores(matchingDocs, acceptDocs, termsEnum);
this.matchingDocsIterator = matchingDocs.iterator();
this.cost = cost;
}
protected void fillDocsAndScores(FixedBitSet matchingDocs, Bits acceptDocs, TermsEnum termsEnum) throws IOException {
@ -378,13 +390,18 @@ class TermsIncludingScoreQuery extends Query {
public int advance(int target) throws IOException {
return currentDoc = matchingDocsIterator.advance(target);
}
@Override
public long cost() {
return cost;
}
}
// This scorer deals with the fact that a document can have more than one score from multiple related documents.
class MVInOrderScorer extends SVInOrderScorer {
MVInOrderScorer(Weight weight, Bits acceptDocs, TermsEnum termsEnum, int maxDoc) throws IOException {
super(weight, acceptDocs, termsEnum, maxDoc);
MVInOrderScorer(Weight weight, Bits acceptDocs, TermsEnum termsEnum, int maxDoc, long cost) throws IOException {
super(weight, acceptDocs, termsEnum, maxDoc, cost);
}
@Override

View File

@ -301,6 +301,11 @@ public class ToChildBlockJoinQuery extends Query {
}
return childDoc;
}
@Override
public long cost() {
return parentScorer.cost();
}
}
@Override

View File

@ -347,6 +347,11 @@ public class ToParentBlockJoinCollector extends Collector {
public int nextDoc() {
throw new UnsupportedOperationException();
}
@Override
public long cost() {
return 1;
}
}
private OneGroup[] sortedGroups;

View File

@ -409,6 +409,10 @@ public class ToParentBlockJoinQuery extends Query {
);
}
@Override
public long cost() {
return childScorer.cost();
}
}
@Override

View File

@ -1020,6 +1020,11 @@ public class MemoryIndex {
public int freq() throws IOException {
return freq;
}
@Override
public long cost() {
return 1;
}
}
private class MemoryDocsAndPositionsEnum extends DocsAndPositionsEnum {
@ -1100,6 +1105,11 @@ public class MemoryIndex {
public BytesRef getPayload() {
return null;
}
@Override
public long cost() {
return 1;
}
}
@Override

View File

@ -348,6 +348,11 @@ public class CustomScoreQuery extends Query {
}
return doc;
}
@Override
public long cost() {
return subQueryScorer.cost();
}
}
@Override

View File

@ -188,6 +188,11 @@ public class BoostedQuery extends Query {
res.addDetail(vals.explain(doc));
return res;
}
@Override
public long cost() {
return scorer.cost();
}
}

View File

@ -158,6 +158,11 @@ public class FunctionQuery extends Query {
return score>Float.NEGATIVE_INFINITY ? score : -Float.MAX_VALUE;
}
@Override
public long cost() {
return maxDoc;
}
@Override
public int freq() throws IOException {
return 1;

View File

@ -91,4 +91,9 @@ public class ValueSourceScorer extends Scorer {
public int freq() throws IOException {
return 1;
}
@Override
public long cost() {
return maxDoc;
}
}

View File

@ -97,6 +97,11 @@ public class TFValueSource extends TermFreqValueSource {
public int advance(int target) {
return DocIdSetIterator.NO_MORE_DOCS;
}
@Override
public long cost() {
return 0;
}
};
}
atDoc = -1;

View File

@ -90,6 +90,11 @@ public class TermFreqValueSource extends DocFreqValueSource {
public int advance(int target) {
return DocIdSetIterator.NO_MORE_DOCS;
}
@Override
public long cost() {
return 0;
}
};
}
atDoc = -1;

View File

@ -433,6 +433,11 @@ public final class RAMOnlyPostingsFormat extends PostingsFormat {
public int docID() {
return current.docID;
}
@Override
public long cost() {
return ramTerm.docs.size();
}
}
private static class RAMDocsAndPositionsEnum extends DocsAndPositionsEnum {
@ -505,6 +510,11 @@ public final class RAMOnlyPostingsFormat extends PostingsFormat {
return null;
}
}
@Override
public long cost() {
return ramTerm.docs.size();
}
}
// Holds all indexes created, keyed by the ID assigned in fieldsConsumer

View File

@ -280,6 +280,11 @@ public abstract class BasePostingsFormatTestCase extends LuceneTestCase {
}
return docID;
}
@Override
public long cost() {
return docFreq;
}
}
private static class FieldAndTerm {

View File

@ -498,6 +498,11 @@ class SpatialDistanceQuery extends ExtendedQueryBase implements PostFilter {
return 1;
}
@Override
public long cost() {
return maxDoc;
}
public Explanation explain(int doc) throws IOException {
advance(doc);
boolean matched = this.doc == doc;

View File

@ -292,6 +292,17 @@ public class BitDocSet extends DocSetBase {
pos = bs.nextSetBit(target+base);
return adjustedDoc = (pos>=0 && pos<max) ? pos-base : NO_MORE_DOCS;
}
@Override
public long cost() {
// we don't want to actually compute cardinality, but
// if its already been computed, we use it
if (size != -1) {
return size;
} else {
return bs.capacity();
}
}
};
}

View File

@ -186,6 +186,11 @@ abstract class DocSetBase implements DocSet {
pos = bs.nextSetBit(target+base);
return adjustedDoc = (pos>=0 && pos<max) ? pos-base : NO_MORE_DOCS;
}
@Override
public long cost() {
return bs.capacity();
}
};
}

View File

@ -546,6 +546,11 @@ class JoinQuery extends Query {
public int advance(int target) throws IOException {
return iter.advance(target);
}
@Override
public long cost() {
return iter.cost();
}
}

View File

@ -196,6 +196,11 @@ public class SolrConstantScoreQuery extends ConstantScoreQuery implements Extend
public int advance(int target) throws IOException {
return docIdSetIterator.advance(target);
}
@Override
public long cost() {
return docIdSetIterator.cost();
}
}
@Override

View File

@ -2307,6 +2307,11 @@ class FilterImpl extends Filter {
public int advance(int target) throws IOException {
return doNext(first.advance(target));
}
@Override
public long cost() {
return first.cost();
}
}
private static class DualFilterIterator extends DocIdSetIterator {
@ -2344,6 +2349,11 @@ class FilterImpl extends Filter {
if (other == doc) return doc;
}
}
@Override
public long cost() {
return Math.min(a.cost(), b.cost());
}
}
}

View File

@ -755,6 +755,10 @@ public class SortedIntDocSet extends DocSetBase {
}
}
@Override
public long cost() {
return docs.length;
}
};
}