mirror of https://github.com/apache/lucene.git
LUCENE-5702: Move comparators to a per-leaf API.
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1649818 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
75f6dd52e4
commit
cdb651976e
|
@ -225,6 +225,9 @@ API Changes
|
||||||
* LUCENE-5527: The Collector API has been refactored to use a dedicated Collector
|
* LUCENE-5527: The Collector API has been refactored to use a dedicated Collector
|
||||||
per leaf. (Shikhar Bhushan, Adrien Grand)
|
per leaf. (Shikhar Bhushan, Adrien Grand)
|
||||||
|
|
||||||
|
* LUCENE-5702: The FieldComparator API has been refactor to a per-leaf API, just
|
||||||
|
like Collectors. (Adrien Grand)
|
||||||
|
|
||||||
* LUCENE-4246: IndexWriter.close now always closes, even if it throws
|
* LUCENE-4246: IndexWriter.close now always closes, even if it throws
|
||||||
an exception. The new IndexWriterConfig.setCommitOnClose (default
|
an exception. The new IndexWriterConfig.setCommitOnClose (default
|
||||||
true) determines whether close() should commit before closing.
|
true) determines whether close() should commit before closing.
|
||||||
|
|
|
@ -17,11 +17,12 @@ package org.apache.lucene.search;
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.apache.lucene.index.LeafReaderContext;
|
|
||||||
import org.apache.lucene.index.BinaryDocValues;
|
import org.apache.lucene.index.BinaryDocValues;
|
||||||
import org.apache.lucene.index.DocValues;
|
import org.apache.lucene.index.DocValues;
|
||||||
|
import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.index.NumericDocValues;
|
import org.apache.lucene.index.NumericDocValues;
|
||||||
import org.apache.lucene.index.SortedDocValues;
|
import org.apache.lucene.index.SortedDocValues;
|
||||||
import org.apache.lucene.util.Bits;
|
import org.apache.lucene.util.Bits;
|
||||||
|
@ -38,46 +39,24 @@ import org.apache.lucene.util.BytesRefBuilder;
|
||||||
* sorting, by exposing a tight interaction with {@link
|
* sorting, by exposing a tight interaction with {@link
|
||||||
* FieldValueHitQueue} as it visits hits. Whenever a hit is
|
* FieldValueHitQueue} as it visits hits. Whenever a hit is
|
||||||
* competitive, it's enrolled into a virtual slot, which is
|
* competitive, it's enrolled into a virtual slot, which is
|
||||||
* an int ranging from 0 to numHits-1. The {@link
|
* an int ranging from 0 to numHits-1. Segment transitions are
|
||||||
* FieldComparator} is made aware of segment transitions
|
* handled by creating a dedicated per-segment
|
||||||
* during searching in case any internal state it's tracking
|
* {@link LeafFieldComparator} which also needs to interact
|
||||||
* needs to be recomputed during these transitions.</p>
|
* with the {@link FieldValueHitQueue} but can optimize based
|
||||||
*
|
* on the segment to collect.</p>
|
||||||
* <p>A comparator must define these functions:</p>
|
*
|
||||||
*
|
* <p>The following functions need to be implemented</p>
|
||||||
* <ul>
|
* <ul>
|
||||||
*
|
|
||||||
* <li> {@link #compare} Compare a hit at 'slot a'
|
* <li> {@link #compare} Compare a hit at 'slot a'
|
||||||
* with hit 'slot b'.
|
* with hit 'slot b'.
|
||||||
*
|
*
|
||||||
* <li> {@link #setBottom} This method is called by
|
|
||||||
* {@link FieldValueHitQueue} to notify the
|
|
||||||
* FieldComparator of the current weakest ("bottom")
|
|
||||||
* slot. Note that this slot may not hold the weakest
|
|
||||||
* value according to your comparator, in cases where
|
|
||||||
* your comparator is not the primary one (ie, is only
|
|
||||||
* used to break ties from the comparators before it).
|
|
||||||
*
|
|
||||||
* <li> {@link #compareBottom} Compare a new hit (docID)
|
|
||||||
* against the "weakest" (bottom) entry in the queue.
|
|
||||||
*
|
|
||||||
* <li> {@link #setTopValue} This method is called by
|
* <li> {@link #setTopValue} This method is called by
|
||||||
* {@link TopFieldCollector} to notify the
|
* {@link TopFieldCollector} to notify the
|
||||||
* FieldComparator of the top most value, which is
|
* FieldComparator of the top most value, which is
|
||||||
* used by future calls to {@link #compareTop}.
|
* used by future calls to
|
||||||
*
|
* {@link LeafFieldComparator#compareTop}.
|
||||||
* <li> {@link #compareBottom} Compare a new hit (docID)
|
*
|
||||||
* against the "weakest" (bottom) entry in the queue.
|
* <li> {@link #getLeafComparator(org.apache.lucene.index.LeafReaderContext)} Invoked
|
||||||
*
|
|
||||||
* <li> {@link #compareTop} Compare a new hit (docID)
|
|
||||||
* against the top value previously set by a call to
|
|
||||||
* {@link #setTopValue}.
|
|
||||||
*
|
|
||||||
* <li> {@link #copy} Installs a new hit into the
|
|
||||||
* priority queue. The {@link FieldValueHitQueue}
|
|
||||||
* calls this method when a new hit is competitive.
|
|
||||||
*
|
|
||||||
* <li> {@link #setNextReader(org.apache.lucene.index.LeafReaderContext)} Invoked
|
|
||||||
* when the search is switching to the next segment.
|
* when the search is switching to the next segment.
|
||||||
* You may need to update internal state of the
|
* You may need to update internal state of the
|
||||||
* comparator, for example retrieving new values from
|
* comparator, for example retrieving new values from
|
||||||
|
@ -89,6 +68,7 @@ import org.apache.lucene.util.BytesRefBuilder;
|
||||||
* FieldDoc#fields} when returning the top results.
|
* FieldDoc#fields} when returning the top results.
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
|
* @see LeafFieldComparator
|
||||||
* @lucene.experimental
|
* @lucene.experimental
|
||||||
*/
|
*/
|
||||||
public abstract class FieldComparator<T> {
|
public abstract class FieldComparator<T> {
|
||||||
|
@ -104,93 +84,14 @@ public abstract class FieldComparator<T> {
|
||||||
*/
|
*/
|
||||||
public abstract int compare(int slot1, int slot2);
|
public abstract int compare(int slot1, int slot2);
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the bottom slot, ie the "weakest" (sorted last)
|
|
||||||
* entry in the queue. When {@link #compareBottom} is
|
|
||||||
* called, you should compare against this slot. This
|
|
||||||
* will always be called before {@link #compareBottom}.
|
|
||||||
*
|
|
||||||
* @param slot the currently weakest (sorted last) slot in the queue
|
|
||||||
*/
|
|
||||||
public abstract void setBottom(final int slot);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Record the top value, for future calls to {@link
|
* Record the top value, for future calls to {@link
|
||||||
* #compareTop}. This is only called for searches that
|
* LeafFieldComparator#compareTop}. This is only called for searches that
|
||||||
* use searchAfter (deep paging), and is called before any
|
* use searchAfter (deep paging), and is called before any
|
||||||
* calls to {@link #setNextReader}.
|
* calls to {@link #getLeafComparator(LeafReaderContext)}.
|
||||||
*/
|
*/
|
||||||
public abstract void setTopValue(T value);
|
public abstract void setTopValue(T value);
|
||||||
|
|
||||||
/**
|
|
||||||
* Compare the bottom of the queue with this doc. This will
|
|
||||||
* only invoked after setBottom has been called. This
|
|
||||||
* should return the same result as {@link
|
|
||||||
* #compare(int,int)}} as if bottom were slot1 and the new
|
|
||||||
* document were slot 2.
|
|
||||||
*
|
|
||||||
* <p>For a search that hits many results, this method
|
|
||||||
* will be the hotspot (invoked by far the most
|
|
||||||
* frequently).</p>
|
|
||||||
*
|
|
||||||
* @param doc that was hit
|
|
||||||
* @return any {@code N < 0} if the doc's value is sorted after
|
|
||||||
* the bottom entry (not competitive), any {@code N > 0} if the
|
|
||||||
* doc's value is sorted before the bottom entry and {@code 0} if
|
|
||||||
* they are equal.
|
|
||||||
*/
|
|
||||||
public abstract int compareBottom(int doc) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compare the top value with this doc. This will
|
|
||||||
* only invoked after setTopValue has been called. This
|
|
||||||
* should return the same result as {@link
|
|
||||||
* #compare(int,int)}} as if topValue were slot1 and the new
|
|
||||||
* document were slot 2. This is only called for searches that
|
|
||||||
* use searchAfter (deep paging).
|
|
||||||
*
|
|
||||||
* @param doc that was hit
|
|
||||||
* @return any {@code N < 0} if the doc's value is sorted after
|
|
||||||
* the bottom entry (not competitive), any {@code N > 0} if the
|
|
||||||
* doc's value is sorted before the bottom entry and {@code 0} if
|
|
||||||
* they are equal.
|
|
||||||
*/
|
|
||||||
public abstract int compareTop(int doc) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called when a new hit is competitive.
|
|
||||||
* You should copy any state associated with this document
|
|
||||||
* that will be required for future comparisons, into the
|
|
||||||
* specified slot.
|
|
||||||
*
|
|
||||||
* @param slot which slot to copy the hit to
|
|
||||||
* @param doc docID relative to current reader
|
|
||||||
*/
|
|
||||||
public abstract void copy(int slot, int doc) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a new {@link org.apache.lucene.index.LeafReaderContext}. All subsequent docIDs are relative to
|
|
||||||
* the current reader (you must add docBase if you need to
|
|
||||||
* map it to a top-level docID).
|
|
||||||
*
|
|
||||||
* @param context current reader context
|
|
||||||
* @return the comparator to use for this segment; most
|
|
||||||
* comparators can just return "this" to reuse the same
|
|
||||||
* comparator across segments
|
|
||||||
* @throws IOException if there is a low-level IO error
|
|
||||||
*/
|
|
||||||
public abstract FieldComparator<T> setNextReader(LeafReaderContext context) throws IOException;
|
|
||||||
|
|
||||||
/** Sets the Scorer to use in case a document's score is
|
|
||||||
* needed.
|
|
||||||
*
|
|
||||||
* @param scorer Scorer instance that you should use to
|
|
||||||
* obtain the current hit's score, if necessary. */
|
|
||||||
public void setScorer(Scorer scorer) {
|
|
||||||
// Empty implementation since most comparators don't need the score. This
|
|
||||||
// can be overridden by those that need it.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the actual value in the slot.
|
* Return the actual value in the slot.
|
||||||
*
|
*
|
||||||
|
@ -199,7 +100,20 @@ public abstract class FieldComparator<T> {
|
||||||
*/
|
*/
|
||||||
public abstract T value(int slot);
|
public abstract T value(int slot);
|
||||||
|
|
||||||
/** Returns -1 if first is less than second. Default
|
/**
|
||||||
|
* Get a per-segment {@link LeafFieldComparator} to collect the given
|
||||||
|
* {@link org.apache.lucene.index.LeafReaderContext}. All docIDs supplied to
|
||||||
|
* this {@link LeafFieldComparator} are relative to the current reader (you
|
||||||
|
* must add docBase if you need to map it to a top-level docID).
|
||||||
|
*
|
||||||
|
* @param context current reader context
|
||||||
|
* @return the comparator to use for this segment
|
||||||
|
* @throws IOException if there is a low-level IO error
|
||||||
|
*/
|
||||||
|
public abstract LeafFieldComparator getLeafComparator(LeafReaderContext context) throws IOException;
|
||||||
|
|
||||||
|
/** Returns a negative integer if first is less than second,
|
||||||
|
* 0 if they are equal and a positive integer otherwise. Default
|
||||||
* impl to assume the type implements Comparable and
|
* impl to assume the type implements Comparable and
|
||||||
* invoke .compareTo; be sure to override this method if
|
* invoke .compareTo; be sure to override this method if
|
||||||
* your FieldComparator's type isn't a Comparable or
|
* your FieldComparator's type isn't a Comparable or
|
||||||
|
@ -219,10 +133,11 @@ public abstract class FieldComparator<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base FieldComparator class for numeric types
|
* Base FieldComparator class for numeric types
|
||||||
*/
|
*/
|
||||||
public static abstract class NumericComparator<T extends Number> extends FieldComparator<T> {
|
public static abstract class NumericComparator<T extends Number> extends SimpleFieldComparator<T> {
|
||||||
protected final T missingValue;
|
protected final T missingValue;
|
||||||
protected final String field;
|
protected final String field;
|
||||||
protected Bits docsWithField;
|
protected Bits docsWithField;
|
||||||
|
@ -234,7 +149,7 @@ public abstract class FieldComparator<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldComparator<T> setNextReader(LeafReaderContext context) throws IOException {
|
protected void doSetNextReader(LeafReaderContext context) throws IOException {
|
||||||
currentReaderValues = getNumericDocValues(context, field);
|
currentReaderValues = getNumericDocValues(context, field);
|
||||||
if (missingValue != null) {
|
if (missingValue != null) {
|
||||||
docsWithField = DocValues.getDocsWithField(context.reader(), field);
|
docsWithField = DocValues.getDocsWithField(context.reader(), field);
|
||||||
|
@ -245,7 +160,6 @@ public abstract class FieldComparator<T> {
|
||||||
} else {
|
} else {
|
||||||
docsWithField = null;
|
docsWithField = null;
|
||||||
}
|
}
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Retrieves the NumericDocValues for the field in this segment */
|
/** Retrieves the NumericDocValues for the field in this segment */
|
||||||
|
@ -551,7 +465,7 @@ public abstract class FieldComparator<T> {
|
||||||
* using {@link TopScoreDocCollector} directly (which {@link
|
* using {@link TopScoreDocCollector} directly (which {@link
|
||||||
* IndexSearcher#search} uses when no {@link Sort} is
|
* IndexSearcher#search} uses when no {@link Sort} is
|
||||||
* specified). */
|
* specified). */
|
||||||
public static final class RelevanceComparator extends FieldComparator<Float> {
|
public static final class RelevanceComparator extends FieldComparator<Float> implements LeafFieldComparator {
|
||||||
private final float[] scores;
|
private final float[] scores;
|
||||||
private float bottom;
|
private float bottom;
|
||||||
private Scorer scorer;
|
private Scorer scorer;
|
||||||
|
@ -581,7 +495,7 @@ public abstract class FieldComparator<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldComparator<Float> setNextReader(LeafReaderContext context) {
|
public LeafFieldComparator getLeafComparator(LeafReaderContext context) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,7 +543,7 @@ public abstract class FieldComparator<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sorts by ascending docID */
|
/** Sorts by ascending docID */
|
||||||
public static final class DocComparator extends FieldComparator<Integer> {
|
public static final class DocComparator extends FieldComparator<Integer> implements LeafFieldComparator {
|
||||||
private final int[] docIDs;
|
private final int[] docIDs;
|
||||||
private int docBase;
|
private int docBase;
|
||||||
private int bottom;
|
private int bottom;
|
||||||
|
@ -658,7 +572,7 @@ public abstract class FieldComparator<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldComparator<Integer> setNextReader(LeafReaderContext context) {
|
public LeafFieldComparator getLeafComparator(LeafReaderContext context) {
|
||||||
// TODO: can we "map" our docIDs to the current
|
// TODO: can we "map" our docIDs to the current
|
||||||
// reader? saves having to then subtract on every
|
// reader? saves having to then subtract on every
|
||||||
// compare call
|
// compare call
|
||||||
|
@ -686,6 +600,9 @@ public abstract class FieldComparator<T> {
|
||||||
int docValue = docBase + doc;
|
int docValue = docBase + doc;
|
||||||
return Integer.compare(topValue, docValue);
|
return Integer.compare(topValue, docValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setScorer(Scorer scorer) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sorts by field's natural Term sort order, using
|
/** Sorts by field's natural Term sort order, using
|
||||||
|
@ -697,7 +614,7 @@ public abstract class FieldComparator<T> {
|
||||||
* to large results, this comparator will be much faster
|
* to large results, this comparator will be much faster
|
||||||
* than {@link org.apache.lucene.search.FieldComparator.TermValComparator}. For very small
|
* than {@link org.apache.lucene.search.FieldComparator.TermValComparator}. For very small
|
||||||
* result sets it may be slower. */
|
* result sets it may be slower. */
|
||||||
public static class TermOrdValComparator extends FieldComparator<BytesRef> {
|
public static class TermOrdValComparator extends FieldComparator<BytesRef> implements LeafFieldComparator {
|
||||||
/* Ords for each slot.
|
/* Ords for each slot.
|
||||||
@lucene.internal */
|
@lucene.internal */
|
||||||
final int[] ords;
|
final int[] ords;
|
||||||
|
@ -841,7 +758,7 @@ public abstract class FieldComparator<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldComparator<BytesRef> setNextReader(LeafReaderContext context) throws IOException {
|
public LeafFieldComparator getLeafComparator(LeafReaderContext context) throws IOException {
|
||||||
termsIndex = getSortedDocValues(context, field);
|
termsIndex = getSortedDocValues(context, field);
|
||||||
currentReaderGen++;
|
currentReaderGen++;
|
||||||
|
|
||||||
|
@ -859,7 +776,7 @@ public abstract class FieldComparator<T> {
|
||||||
topOrd = missingOrd;
|
topOrd = missingOrd;
|
||||||
topSameReader = true;
|
topSameReader = true;
|
||||||
}
|
}
|
||||||
//System.out.println(" setNextReader topOrd=" + topOrd + " topSameReader=" + topSameReader);
|
//System.out.println(" getLeafComparator topOrd=" + topOrd + " topSameReader=" + topSameReader);
|
||||||
|
|
||||||
if (bottomSlot != -1) {
|
if (bottomSlot != -1) {
|
||||||
// Recompute bottomOrd/SameReader
|
// Recompute bottomOrd/SameReader
|
||||||
|
@ -947,13 +864,16 @@ public abstract class FieldComparator<T> {
|
||||||
}
|
}
|
||||||
return val1.compareTo(val2);
|
return val1.compareTo(val2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setScorer(Scorer scorer) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sorts by field's natural Term sort order. All
|
/** Sorts by field's natural Term sort order. All
|
||||||
* comparisons are done using BytesRef.compareTo, which is
|
* comparisons are done using BytesRef.compareTo, which is
|
||||||
* slow for medium to large result sets but possibly
|
* slow for medium to large result sets but possibly
|
||||||
* very fast for very small results sets. */
|
* very fast for very small results sets. */
|
||||||
public static class TermValComparator extends FieldComparator<BytesRef> {
|
public static class TermValComparator extends FieldComparator<BytesRef> implements LeafFieldComparator {
|
||||||
|
|
||||||
private final BytesRef[] values;
|
private final BytesRef[] values;
|
||||||
private final BytesRefBuilder[] tempBRs;
|
private final BytesRefBuilder[] tempBRs;
|
||||||
|
@ -1019,7 +939,7 @@ public abstract class FieldComparator<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldComparator<BytesRef> setNextReader(LeafReaderContext context) throws IOException {
|
public LeafFieldComparator getLeafComparator(LeafReaderContext context) throws IOException {
|
||||||
docTerms = getBinaryDocValues(context, field);
|
docTerms = getBinaryDocValues(context, field);
|
||||||
docsWithField = getDocsWithField(context, field);
|
docsWithField = getDocsWithField(context, field);
|
||||||
if (docsWithField instanceof Bits.MatchAllBits) {
|
if (docsWithField instanceof Bits.MatchAllBits) {
|
||||||
|
@ -1075,5 +995,8 @@ public abstract class FieldComparator<T> {
|
||||||
}
|
}
|
||||||
return term;
|
return term;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setScorer(Scorer scorer) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.lucene.search;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.util.PriorityQueue;
|
import org.apache.lucene.util.PriorityQueue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,17 +54,17 @@ public abstract class FieldValueHitQueue<T extends FieldValueHitQueue.Entry> ext
|
||||||
* there is just one comparator.
|
* there is just one comparator.
|
||||||
*/
|
*/
|
||||||
private static final class OneComparatorFieldValueHitQueue<T extends FieldValueHitQueue.Entry> extends FieldValueHitQueue<T> {
|
private static final class OneComparatorFieldValueHitQueue<T extends FieldValueHitQueue.Entry> extends FieldValueHitQueue<T> {
|
||||||
|
|
||||||
private final int oneReverseMul;
|
private final int oneReverseMul;
|
||||||
|
private final FieldComparator<?> oneComparator;
|
||||||
|
|
||||||
public OneComparatorFieldValueHitQueue(SortField[] fields, int size)
|
public OneComparatorFieldValueHitQueue(SortField[] fields, int size)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
super(fields, size);
|
super(fields, size);
|
||||||
|
|
||||||
SortField field = fields[0];
|
assert fields.length == 1;
|
||||||
setComparator(0,field.getComparator(size, 0));
|
oneComparator = comparators[0];
|
||||||
oneReverseMul = field.reverse ? -1 : 1;
|
oneReverseMul = reverseMul[0];
|
||||||
|
|
||||||
reverseMul[0] = oneReverseMul;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,7 +79,7 @@ public abstract class FieldValueHitQueue<T extends FieldValueHitQueue.Entry> ext
|
||||||
assert hitA != hitB;
|
assert hitA != hitB;
|
||||||
assert hitA.slot != hitB.slot;
|
assert hitA.slot != hitB.slot;
|
||||||
|
|
||||||
final int c = oneReverseMul * firstComparator.compare(hitA.slot, hitB.slot);
|
final int c = oneReverseMul * oneComparator.compare(hitA.slot, hitB.slot);
|
||||||
if (c != 0) {
|
if (c != 0) {
|
||||||
return c > 0;
|
return c > 0;
|
||||||
}
|
}
|
||||||
|
@ -98,14 +99,6 @@ public abstract class FieldValueHitQueue<T extends FieldValueHitQueue.Entry> ext
|
||||||
public MultiComparatorsFieldValueHitQueue(SortField[] fields, int size)
|
public MultiComparatorsFieldValueHitQueue(SortField[] fields, int size)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
super(fields, size);
|
super(fields, size);
|
||||||
|
|
||||||
int numComparators = comparators.length;
|
|
||||||
for (int i = 0; i < numComparators; ++i) {
|
|
||||||
SortField field = fields[i];
|
|
||||||
|
|
||||||
reverseMul[i] = field.reverse ? -1 : 1;
|
|
||||||
setComparator(i, field.getComparator(size, i));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -130,8 +123,7 @@ public abstract class FieldValueHitQueue<T extends FieldValueHitQueue.Entry> ext
|
||||||
}
|
}
|
||||||
|
|
||||||
// prevent instantiation and extension.
|
// prevent instantiation and extension.
|
||||||
@SuppressWarnings({"rawtypes","unchecked"})
|
private FieldValueHitQueue(SortField[] fields, int size) throws IOException {
|
||||||
private FieldValueHitQueue(SortField[] fields, int size) {
|
|
||||||
super(size);
|
super(size);
|
||||||
// When we get here, fields.length is guaranteed to be > 0, therefore no
|
// When we get here, fields.length is guaranteed to be > 0, therefore no
|
||||||
// need to check it again.
|
// need to check it again.
|
||||||
|
@ -141,8 +133,14 @@ public abstract class FieldValueHitQueue<T extends FieldValueHitQueue.Entry> ext
|
||||||
// anyway.
|
// anyway.
|
||||||
this.fields = fields;
|
this.fields = fields;
|
||||||
int numComparators = fields.length;
|
int numComparators = fields.length;
|
||||||
comparators = new FieldComparator[numComparators];
|
comparators = new FieldComparator<?>[numComparators];
|
||||||
reverseMul = new int[numComparators];
|
reverseMul = new int[numComparators];
|
||||||
|
for (int i = 0; i < numComparators; ++i) {
|
||||||
|
SortField field = fields[i];
|
||||||
|
|
||||||
|
reverseMul[i] = field.reverse ? -1 : 1;
|
||||||
|
comparators[i] = field.getComparator(size, i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -179,15 +177,17 @@ public abstract class FieldValueHitQueue<T extends FieldValueHitQueue.Entry> ext
|
||||||
return reverseMul;
|
return reverseMul;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setComparator(int pos, FieldComparator<?> comparator) {
|
public LeafFieldComparator[] getComparators(LeafReaderContext context) throws IOException {
|
||||||
if (pos==0) firstComparator = comparator;
|
LeafFieldComparator[] comparators = new LeafFieldComparator[this.comparators.length];
|
||||||
comparators[pos] = comparator;
|
for (int i = 0; i < comparators.length; ++i) {
|
||||||
|
comparators[i] = this.comparators[i].getLeafComparator(context);
|
||||||
|
}
|
||||||
|
return comparators;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Stores the sort criteria being used. */
|
/** Stores the sort criteria being used. */
|
||||||
protected final SortField[] fields;
|
protected final SortField[] fields;
|
||||||
protected final FieldComparator<?>[] comparators; // use setComparator to change this array
|
protected final FieldComparator<?>[] comparators;
|
||||||
protected FieldComparator<?> firstComparator; // this must always be equal to comparators[0]
|
|
||||||
protected final int[] reverseMul;
|
protected final int[] reverseMul;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expert: comparator that gets instantiated on each leaf
|
||||||
|
* from a top-level {@link FieldComparator} instance.
|
||||||
|
*
|
||||||
|
* <p>A leaf comparator must define these functions:</p>
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
*
|
||||||
|
* <li> {@link #setBottom} This method is called by
|
||||||
|
* {@link FieldValueHitQueue} to notify the
|
||||||
|
* FieldComparator of the current weakest ("bottom")
|
||||||
|
* slot. Note that this slot may not hold the weakest
|
||||||
|
* value according to your comparator, in cases where
|
||||||
|
* your comparator is not the primary one (ie, is only
|
||||||
|
* used to break ties from the comparators before it).
|
||||||
|
*
|
||||||
|
* <li> {@link #compareBottom} Compare a new hit (docID)
|
||||||
|
* against the "weakest" (bottom) entry in the queue.
|
||||||
|
*
|
||||||
|
* <li> {@link #compareBottom} Compare a new hit (docID)
|
||||||
|
* against the "weakest" (bottom) entry in the queue.
|
||||||
|
*
|
||||||
|
* <li> {@link #compareTop} Compare a new hit (docID)
|
||||||
|
* against the top value previously set by a call to
|
||||||
|
* {@link FieldComparator#setTopValue}.
|
||||||
|
*
|
||||||
|
* <li> {@link #copy} Installs a new hit into the
|
||||||
|
* priority queue. The {@link FieldValueHitQueue}
|
||||||
|
* calls this method when a new hit is competitive.
|
||||||
|
*
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @see FieldComparator
|
||||||
|
* @lucene.experimental
|
||||||
|
*/
|
||||||
|
public interface LeafFieldComparator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the bottom slot, ie the "weakest" (sorted last)
|
||||||
|
* entry in the queue. When {@link #compareBottom} is
|
||||||
|
* called, you should compare against this slot. This
|
||||||
|
* will always be called before {@link #compareBottom}.
|
||||||
|
*
|
||||||
|
* @param slot the currently weakest (sorted last) slot in the queue
|
||||||
|
*/
|
||||||
|
void setBottom(final int slot);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare the bottom of the queue with this doc. This will
|
||||||
|
* only invoked after setBottom has been called. This
|
||||||
|
* should return the same result as {@link
|
||||||
|
* FieldComparator#compare(int,int)}} as if bottom were slot1 and the new
|
||||||
|
* document were slot 2.
|
||||||
|
*
|
||||||
|
* <p>For a search that hits many results, this method
|
||||||
|
* will be the hotspot (invoked by far the most
|
||||||
|
* frequently).</p>
|
||||||
|
*
|
||||||
|
* @param doc that was hit
|
||||||
|
* @return any {@code N < 0} if the doc's value is sorted after
|
||||||
|
* the bottom entry (not competitive), any {@code N > 0} if the
|
||||||
|
* doc's value is sorted before the bottom entry and {@code 0} if
|
||||||
|
* they are equal.
|
||||||
|
*/
|
||||||
|
int compareBottom(int doc) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare the top value with this doc. This will
|
||||||
|
* only invoked after setTopValue has been called. This
|
||||||
|
* should return the same result as {@link
|
||||||
|
* FieldComparator#compare(int,int)}} as if topValue were slot1 and the new
|
||||||
|
* document were slot 2. This is only called for searches that
|
||||||
|
* use searchAfter (deep paging).
|
||||||
|
*
|
||||||
|
* @param doc that was hit
|
||||||
|
* @return any {@code N < 0} if the doc's value is sorted after
|
||||||
|
* the bottom entry (not competitive), any {@code N > 0} if the
|
||||||
|
* doc's value is sorted before the bottom entry and {@code 0} if
|
||||||
|
* they are equal.
|
||||||
|
*/
|
||||||
|
int compareTop(int doc) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called when a new hit is competitive.
|
||||||
|
* You should copy any state associated with this document
|
||||||
|
* that will be required for future comparisons, into the
|
||||||
|
* specified slot.
|
||||||
|
*
|
||||||
|
* @param slot which slot to copy the hit to
|
||||||
|
* @param doc docID relative to current reader
|
||||||
|
*/
|
||||||
|
void copy(int slot, int doc) throws IOException;
|
||||||
|
|
||||||
|
/** Sets the Scorer to use in case a document's score is
|
||||||
|
* needed.
|
||||||
|
*
|
||||||
|
* @param scorer Scorer instance that you should use to
|
||||||
|
* obtain the current hit's score, if necessary. */
|
||||||
|
void setScorer(Scorer scorer);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
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 org.apache.lucene.index.LeafReaderContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base {@link FieldComparator} implementation that is used for all contexts.
|
||||||
|
*
|
||||||
|
* @lucene.experimental
|
||||||
|
*/
|
||||||
|
public abstract class SimpleFieldComparator<T> extends FieldComparator<T> implements LeafFieldComparator {
|
||||||
|
|
||||||
|
/** This method is called before collecting <code>context</code>. */
|
||||||
|
protected abstract void doSetNextReader(LeafReaderContext context) throws IOException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final LeafFieldComparator getLeafComparator(LeafReaderContext context) throws IOException {
|
||||||
|
doSetNextReader(context);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setScorer(Scorer scorer) {}
|
||||||
|
}
|
|
@ -61,6 +61,7 @@ public class SortRescorer extends Rescorer {
|
||||||
int endDoc = 0;
|
int endDoc = 0;
|
||||||
int docBase = 0;
|
int docBase = 0;
|
||||||
|
|
||||||
|
LeafCollector leafCollector = null;
|
||||||
FakeScorer fakeScorer = new FakeScorer();
|
FakeScorer fakeScorer = new FakeScorer();
|
||||||
|
|
||||||
while (hitUpto < hits.length) {
|
while (hitUpto < hits.length) {
|
||||||
|
@ -75,15 +76,15 @@ public class SortRescorer extends Rescorer {
|
||||||
|
|
||||||
if (readerContext != null) {
|
if (readerContext != null) {
|
||||||
// We advanced to another segment:
|
// We advanced to another segment:
|
||||||
collector.getLeafCollector(readerContext);
|
leafCollector = collector.getLeafCollector(readerContext);
|
||||||
collector.setScorer(fakeScorer);
|
leafCollector.setScorer(fakeScorer);
|
||||||
docBase = readerContext.docBase;
|
docBase = readerContext.docBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
fakeScorer.score = hit.score;
|
fakeScorer.score = hit.score;
|
||||||
fakeScorer.doc = docID - docBase;
|
fakeScorer.doc = docID - docBase;
|
||||||
|
|
||||||
collector.collect(fakeScorer.doc);
|
leafCollector.collect(fakeScorer.doc);
|
||||||
|
|
||||||
hitUpto++;
|
hitUpto++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ import org.apache.lucene.util.PriorityQueue;
|
||||||
* however, you might want to consider overriding all methods, in order to avoid
|
* however, you might want to consider overriding all methods, in order to avoid
|
||||||
* a NullPointerException.
|
* a NullPointerException.
|
||||||
*/
|
*/
|
||||||
public abstract class TopDocsCollector<T extends ScoreDoc> extends SimpleCollector {
|
public abstract class TopDocsCollector<T extends ScoreDoc> implements Collector {
|
||||||
|
|
||||||
/** This is used in case topDocs() is called with illegal parameters, or there
|
/** This is used in case topDocs() is called with illegal parameters, or there
|
||||||
* simply aren't (enough) results. */
|
* simply aren't (enough) results. */
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -36,198 +36,189 @@ import org.apache.lucene.index.LeafReaderContext;
|
||||||
*/
|
*/
|
||||||
public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
|
public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
|
||||||
|
|
||||||
// Assumes docs are scored in order.
|
private abstract static class ScorerLeafCollector implements LeafCollector {
|
||||||
private static class InOrderTopScoreDocCollector extends TopScoreDocCollector {
|
|
||||||
private InOrderTopScoreDocCollector(int numHits) {
|
final boolean scoreDocsInOrder;
|
||||||
super(numHits);
|
|
||||||
|
ScorerLeafCollector(boolean scoreDocsInOrder) {
|
||||||
|
this.scoreDocsInOrder = scoreDocsInOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Scorer scorer;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void collect(int doc) throws IOException {
|
public void setScorer(Scorer scorer) throws IOException {
|
||||||
float score = scorer.score();
|
this.scorer = scorer;
|
||||||
|
|
||||||
// This collector cannot handle these scores:
|
|
||||||
assert score != Float.NEGATIVE_INFINITY;
|
|
||||||
assert !Float.isNaN(score);
|
|
||||||
|
|
||||||
totalHits++;
|
|
||||||
if (score <= pqTop.score) {
|
|
||||||
// Since docs are returned in-order (i.e., increasing doc Id), a document
|
|
||||||
// with equal score to pqTop.score cannot compete since HitQueue favors
|
|
||||||
// documents with lower doc Ids. Therefore reject those docs too.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pqTop.doc = doc + docBase;
|
|
||||||
pqTop.score = score;
|
|
||||||
pqTop = pq.updateTop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean acceptsDocsOutOfOrder() {
|
public boolean acceptsDocsOutOfOrder() {
|
||||||
return false;
|
return scoreDocsInOrder == false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assumes docs are scored in order.
|
private static class SimpleTopScoreDocCollector extends TopScoreDocCollector {
|
||||||
private static class InOrderPagingScoreDocCollector extends TopScoreDocCollector {
|
|
||||||
|
private final boolean scoreDocsInOrder;
|
||||||
|
|
||||||
|
SimpleTopScoreDocCollector(int numHits, boolean scoreDocsInOrder) {
|
||||||
|
super(numHits);
|
||||||
|
this.scoreDocsInOrder = scoreDocsInOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LeafCollector getLeafCollector(LeafReaderContext context)
|
||||||
|
throws IOException {
|
||||||
|
final int docBase = context.docBase;
|
||||||
|
if (scoreDocsInOrder) {
|
||||||
|
return new ScorerLeafCollector(scoreDocsInOrder) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void collect(int doc) throws IOException {
|
||||||
|
float score = scorer.score();
|
||||||
|
|
||||||
|
// This collector cannot handle these scores:
|
||||||
|
assert score != Float.NEGATIVE_INFINITY;
|
||||||
|
assert !Float.isNaN(score);
|
||||||
|
|
||||||
|
totalHits++;
|
||||||
|
if (score <= pqTop.score) {
|
||||||
|
// Since docs are returned in-order (i.e., increasing doc Id), a document
|
||||||
|
// with equal score to pqTop.score cannot compete since HitQueue favors
|
||||||
|
// documents with lower doc Ids. Therefore reject those docs too.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pqTop.doc = doc + docBase;
|
||||||
|
pqTop.score = score;
|
||||||
|
pqTop = pq.updateTop();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return new ScorerLeafCollector(scoreDocsInOrder) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void collect(int doc) throws IOException {
|
||||||
|
float score = scorer.score();
|
||||||
|
|
||||||
|
// This collector cannot handle NaN
|
||||||
|
assert !Float.isNaN(score);
|
||||||
|
|
||||||
|
totalHits++;
|
||||||
|
if (score < pqTop.score) {
|
||||||
|
// Doesn't compete w/ bottom entry in queue
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
doc += docBase;
|
||||||
|
if (score == pqTop.score && doc > pqTop.doc) {
|
||||||
|
// Break tie in score by doc ID:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pqTop.doc = doc;
|
||||||
|
pqTop.score = score;
|
||||||
|
pqTop = pq.updateTop();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PagingTopScoreDocCollector extends TopScoreDocCollector {
|
||||||
|
|
||||||
|
private final boolean scoreDocsInOrder;
|
||||||
private final ScoreDoc after;
|
private final ScoreDoc after;
|
||||||
// this is always after.doc - docBase, to save an add when score == after.score
|
|
||||||
private int afterDoc;
|
|
||||||
private int collectedHits;
|
private int collectedHits;
|
||||||
|
|
||||||
private InOrderPagingScoreDocCollector(ScoreDoc after, int numHits) {
|
PagingTopScoreDocCollector(int numHits, boolean scoreDocsInOrder, ScoreDoc after) {
|
||||||
super(numHits);
|
super(numHits);
|
||||||
|
this.scoreDocsInOrder = scoreDocsInOrder;
|
||||||
this.after = after;
|
this.after = after;
|
||||||
}
|
this.collectedHits = 0;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void collect(int doc) throws IOException {
|
|
||||||
float score = scorer.score();
|
|
||||||
|
|
||||||
// This collector cannot handle these scores:
|
|
||||||
assert score != Float.NEGATIVE_INFINITY;
|
|
||||||
assert !Float.isNaN(score);
|
|
||||||
|
|
||||||
totalHits++;
|
|
||||||
|
|
||||||
if (score > after.score || (score == after.score && doc <= afterDoc)) {
|
|
||||||
// hit was collected on a previous page
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (score <= pqTop.score) {
|
|
||||||
// Since docs are returned in-order (i.e., increasing doc Id), a document
|
|
||||||
// with equal score to pqTop.score cannot compete since HitQueue favors
|
|
||||||
// documents with lower doc Ids. Therefore reject those docs too.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
collectedHits++;
|
|
||||||
pqTop.doc = doc + docBase;
|
|
||||||
pqTop.score = score;
|
|
||||||
pqTop = pq.updateTop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean acceptsDocsOutOfOrder() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doSetNextReader(LeafReaderContext context) throws IOException {
|
|
||||||
super.doSetNextReader(context);
|
|
||||||
afterDoc = after.doc - context.docBase;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int topDocsSize() {
|
protected int topDocsSize() {
|
||||||
return collectedHits < pq.size() ? collectedHits : pq.size();
|
return collectedHits < pq.size() ? collectedHits : pq.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TopDocs newTopDocs(ScoreDoc[] results, int start) {
|
protected TopDocs newTopDocs(ScoreDoc[] results, int start) {
|
||||||
return results == null ? new TopDocs(totalHits, new ScoreDoc[0], Float.NaN) : new TopDocs(totalHits, results);
|
return results == null ? new TopDocs(totalHits, new ScoreDoc[0], Float.NaN) : new TopDocs(totalHits, results);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Assumes docs are scored out of order.
|
|
||||||
private static class OutOfOrderTopScoreDocCollector extends TopScoreDocCollector {
|
|
||||||
private OutOfOrderTopScoreDocCollector(int numHits) {
|
|
||||||
super(numHits);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void collect(int doc) throws IOException {
|
public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException {
|
||||||
float score = scorer.score();
|
final int docBase = context.docBase;
|
||||||
|
final int afterDoc = after.doc - context.docBase;
|
||||||
|
if (scoreDocsInOrder) {
|
||||||
|
return new ScorerLeafCollector(scoreDocsInOrder) {
|
||||||
|
@Override
|
||||||
|
public void collect(int doc) throws IOException {
|
||||||
|
float score = scorer.score();
|
||||||
|
|
||||||
// This collector cannot handle NaN
|
// This collector cannot handle these scores:
|
||||||
assert !Float.isNaN(score);
|
assert score != Float.NEGATIVE_INFINITY;
|
||||||
|
assert !Float.isNaN(score);
|
||||||
|
|
||||||
totalHits++;
|
totalHits++;
|
||||||
if (score < pqTop.score) {
|
|
||||||
// Doesn't compete w/ bottom entry in queue
|
if (score > after.score || (score == after.score && doc <= afterDoc)) {
|
||||||
return;
|
// hit was collected on a previous page
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (score <= pqTop.score) {
|
||||||
|
// Since docs are returned in-order (i.e., increasing doc Id), a document
|
||||||
|
// with equal score to pqTop.score cannot compete since HitQueue favors
|
||||||
|
// documents with lower doc Ids. Therefore reject those docs too.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
collectedHits++;
|
||||||
|
pqTop.doc = doc + docBase;
|
||||||
|
pqTop.score = score;
|
||||||
|
pqTop = pq.updateTop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return new ScorerLeafCollector(scoreDocsInOrder) {
|
||||||
|
@Override
|
||||||
|
public void collect(int doc) throws IOException {
|
||||||
|
float score = scorer.score();
|
||||||
|
|
||||||
|
// This collector cannot handle NaN
|
||||||
|
assert !Float.isNaN(score);
|
||||||
|
|
||||||
|
totalHits++;
|
||||||
|
if (score > after.score || (score == after.score && doc <= afterDoc)) {
|
||||||
|
// hit was collected on a previous page
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (score < pqTop.score) {
|
||||||
|
// Doesn't compete w/ bottom entry in queue
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
doc += docBase;
|
||||||
|
if (score == pqTop.score && doc > pqTop.doc) {
|
||||||
|
// Break tie in score by doc ID:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
collectedHits++;
|
||||||
|
pqTop.doc = doc;
|
||||||
|
pqTop.score = score;
|
||||||
|
pqTop = pq.updateTop();
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
doc += docBase;
|
|
||||||
if (score == pqTop.score && doc > pqTop.doc) {
|
|
||||||
// Break tie in score by doc ID:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pqTop.doc = doc;
|
|
||||||
pqTop.score = score;
|
|
||||||
pqTop = pq.updateTop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean acceptsDocsOutOfOrder() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assumes docs are scored out of order.
|
|
||||||
private static class OutOfOrderPagingScoreDocCollector extends TopScoreDocCollector {
|
|
||||||
private final ScoreDoc after;
|
|
||||||
// this is always after.doc - docBase, to save an add when score == after.score
|
|
||||||
private int afterDoc;
|
|
||||||
private int collectedHits;
|
|
||||||
|
|
||||||
private OutOfOrderPagingScoreDocCollector(ScoreDoc after, int numHits) {
|
|
||||||
super(numHits);
|
|
||||||
this.after = after;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void collect(int doc) throws IOException {
|
|
||||||
float score = scorer.score();
|
|
||||||
|
|
||||||
// This collector cannot handle NaN
|
|
||||||
assert !Float.isNaN(score);
|
|
||||||
|
|
||||||
totalHits++;
|
|
||||||
if (score > after.score || (score == after.score && doc <= afterDoc)) {
|
|
||||||
// hit was collected on a previous page
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (score < pqTop.score) {
|
|
||||||
// Doesn't compete w/ bottom entry in queue
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
doc += docBase;
|
|
||||||
if (score == pqTop.score && doc > pqTop.doc) {
|
|
||||||
// Break tie in score by doc ID:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
collectedHits++;
|
|
||||||
pqTop.doc = doc;
|
|
||||||
pqTop.score = score;
|
|
||||||
pqTop = pq.updateTop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean acceptsDocsOutOfOrder() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doSetNextReader(LeafReaderContext context) throws IOException {
|
|
||||||
super.doSetNextReader(context);
|
|
||||||
afterDoc = after.doc - context.docBase;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int topDocsSize() {
|
|
||||||
return collectedHits < pq.size() ? collectedHits : pq.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected TopDocs newTopDocs(ScoreDoc[] results, int start) {
|
|
||||||
return results == null ? new TopDocs(totalHits, new ScoreDoc[0], Float.NaN) : new TopDocs(totalHits, results);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link TopScoreDocCollector} given the number of hits to
|
* Creates a new {@link TopScoreDocCollector} given the number of hits to
|
||||||
* collect and whether documents are scored in order by the input
|
* collect and whether documents are scored in order by the input
|
||||||
* {@link Scorer} to {@link #setScorer(Scorer)}.
|
* {@link Scorer} to {@link LeafCollector#setScorer(Scorer)}.
|
||||||
*
|
*
|
||||||
* <p><b>NOTE</b>: The instances returned by this method
|
* <p><b>NOTE</b>: The instances returned by this method
|
||||||
* pre-allocate a full array of length
|
* pre-allocate a full array of length
|
||||||
|
@ -237,11 +228,11 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
|
||||||
public static TopScoreDocCollector create(int numHits, boolean docsScoredInOrder) {
|
public static TopScoreDocCollector create(int numHits, boolean docsScoredInOrder) {
|
||||||
return create(numHits, null, docsScoredInOrder);
|
return create(numHits, null, docsScoredInOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link TopScoreDocCollector} given the number of hits to
|
* Creates a new {@link TopScoreDocCollector} given the number of hits to
|
||||||
* collect, the bottom of the previous page, and whether documents are scored in order by the input
|
* collect, the bottom of the previous page, and whether documents are scored in order by the input
|
||||||
* {@link Scorer} to {@link #setScorer(Scorer)}.
|
* {@link Scorer} to {@link LeafCollector#setScorer(Scorer)}.
|
||||||
*
|
*
|
||||||
* <p><b>NOTE</b>: The instances returned by this method
|
* <p><b>NOTE</b>: The instances returned by this method
|
||||||
* pre-allocate a full array of length
|
* pre-allocate a full array of length
|
||||||
|
@ -249,27 +240,20 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
|
||||||
* objects.
|
* objects.
|
||||||
*/
|
*/
|
||||||
public static TopScoreDocCollector create(int numHits, ScoreDoc after, boolean docsScoredInOrder) {
|
public static TopScoreDocCollector create(int numHits, ScoreDoc after, boolean docsScoredInOrder) {
|
||||||
|
|
||||||
if (numHits <= 0) {
|
if (numHits <= 0) {
|
||||||
throw new IllegalArgumentException("numHits must be > 0; please use TotalHitCountCollector if you just need the total hit count");
|
throw new IllegalArgumentException("numHits must be > 0; please use TotalHitCountCollector if you just need the total hit count");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (docsScoredInOrder) {
|
if (after == null) {
|
||||||
return after == null
|
return new SimpleTopScoreDocCollector(numHits, docsScoredInOrder);
|
||||||
? new InOrderTopScoreDocCollector(numHits)
|
|
||||||
: new InOrderPagingScoreDocCollector(after, numHits);
|
|
||||||
} else {
|
} else {
|
||||||
return after == null
|
return new PagingTopScoreDocCollector(numHits, docsScoredInOrder, after);
|
||||||
? new OutOfOrderTopScoreDocCollector(numHits)
|
|
||||||
: new OutOfOrderPagingScoreDocCollector(after, numHits);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScoreDoc pqTop;
|
ScoreDoc pqTop;
|
||||||
int docBase = 0;
|
|
||||||
Scorer scorer;
|
|
||||||
|
|
||||||
// prevents instantiation
|
// prevents instantiation
|
||||||
private TopScoreDocCollector(int numHits) {
|
private TopScoreDocCollector(int numHits) {
|
||||||
super(new HitQueue(numHits, true));
|
super(new HitQueue(numHits, true));
|
||||||
|
@ -283,7 +267,7 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
|
||||||
if (results == null) {
|
if (results == null) {
|
||||||
return EMPTY_TOPDOCS;
|
return EMPTY_TOPDOCS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to compute maxScore in order to set it in TopDocs. If start == 0,
|
// We need to compute maxScore in order to set it in TopDocs. If start == 0,
|
||||||
// it means the largest element is already in results, use its score as
|
// it means the largest element is already in results, use its score as
|
||||||
// maxScore. Otherwise pop everything else, until the largest element is
|
// maxScore. Otherwise pop everything else, until the largest element is
|
||||||
|
@ -295,17 +279,7 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
|
||||||
for (int i = pq.size(); i > 1; i--) { pq.pop(); }
|
for (int i = pq.size(); i > 1; i--) { pq.pop(); }
|
||||||
maxScore = pq.pop().score;
|
maxScore = pq.pop().score;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new TopDocs(totalHits, results, maxScore);
|
return new TopDocs(totalHits, results, maxScore);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doSetNextReader(LeafReaderContext context) throws IOException {
|
|
||||||
docBase = context.docBase;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setScorer(Scorer scorer) throws IOException {
|
|
||||||
this.scorer = scorer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,43 +98,23 @@ final class JustCompileSearch {
|
||||||
|
|
||||||
static final class JustCompileFieldComparator extends FieldComparator<Object> {
|
static final class JustCompileFieldComparator extends FieldComparator<Object> {
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(int slot1, int slot2) {
|
|
||||||
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareBottom(int doc) {
|
|
||||||
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void copy(int slot, int doc) {
|
|
||||||
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBottom(int slot) {
|
|
||||||
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTopValue(Object value) {
|
public void setTopValue(Object value) {
|
||||||
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
|
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public FieldComparator<Object> setNextReader(LeafReaderContext context) {
|
|
||||||
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object value(int slot) {
|
public Object value(int slot) {
|
||||||
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
|
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTop(int doc) {
|
public LeafFieldComparator getLeafComparator(LeafReaderContext context) throws IOException {
|
||||||
|
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(int slot1, int slot2) {
|
||||||
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
|
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,23 +240,8 @@ final class JustCompileSearch {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void collect(int doc) {
|
public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException {
|
||||||
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
|
throw new UnsupportedOperationException( UNSUPPORTED_MSG );
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doSetNextReader(LeafReaderContext context) throws IOException {
|
|
||||||
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setScorer(Scorer scorer) {
|
|
||||||
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean acceptsDocsOutOfOrder() {
|
|
||||||
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.apache.lucene.search.similarities.DefaultSimilarity;
|
||||||
import org.apache.lucene.store.*;
|
import org.apache.lucene.store.*;
|
||||||
import org.apache.lucene.util.LuceneTestCase;
|
import org.apache.lucene.util.LuceneTestCase;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -146,61 +147,67 @@ class ElevationComparatorSource extends FieldComparatorSource {
|
||||||
public FieldComparator<Integer> newComparator(final String fieldname, final int numHits, int sortPos, boolean reversed) throws IOException {
|
public FieldComparator<Integer> newComparator(final String fieldname, final int numHits, int sortPos, boolean reversed) throws IOException {
|
||||||
return new FieldComparator<Integer>() {
|
return new FieldComparator<Integer>() {
|
||||||
|
|
||||||
SortedDocValues idIndex;
|
|
||||||
private final int[] values = new int[numHits];
|
private final int[] values = new int[numHits];
|
||||||
int bottomVal;
|
int bottomVal;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LeafFieldComparator getLeafComparator(LeafReaderContext context)
|
||||||
|
throws IOException {
|
||||||
|
final SortedDocValues idIndex = DocValues.getSorted(context.reader(), fieldname);
|
||||||
|
return new LeafFieldComparator() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBottom(int slot) {
|
||||||
|
bottomVal = values[slot];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTop(int doc) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int docVal(int doc) {
|
||||||
|
int ord = idIndex.getOrd(doc);
|
||||||
|
if (ord == -1) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
final BytesRef term = idIndex.lookupOrd(ord);
|
||||||
|
Integer prio = priority.get(term);
|
||||||
|
return prio == null ? 0 : prio.intValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareBottom(int doc) {
|
||||||
|
return docVal(doc) - bottomVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copy(int slot, int doc) {
|
||||||
|
values[slot] = docVal(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setScorer(Scorer scorer) {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(int slot1, int slot2) {
|
public int compare(int slot1, int slot2) {
|
||||||
return values[slot2] - values[slot1]; // values will be small enough that there is no overflow concern
|
return values[slot2] - values[slot1]; // values will be small enough that there is no overflow concern
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBottom(int slot) {
|
|
||||||
bottomVal = values[slot];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTopValue(Integer value) {
|
public void setTopValue(Integer value) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int docVal(int doc) {
|
|
||||||
int ord = idIndex.getOrd(doc);
|
|
||||||
if (ord == -1) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
final BytesRef term = idIndex.lookupOrd(ord);
|
|
||||||
Integer prio = priority.get(term);
|
|
||||||
return prio == null ? 0 : prio.intValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareBottom(int doc) {
|
|
||||||
return docVal(doc) - bottomVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void copy(int slot, int doc) {
|
|
||||||
values[slot] = docVal(doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FieldComparator<Integer> setNextReader(LeafReaderContext context) throws IOException {
|
|
||||||
idIndex = DocValues.getSorted(context.reader(), fieldname);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer value(int slot) {
|
public Integer value(int slot) {
|
||||||
return Integer.valueOf(values[slot]);
|
return Integer.valueOf(values[slot]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTop(int doc) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -785,4 +785,63 @@ public class TestSort extends LuceneTestCase {
|
||||||
ir.close();
|
ir.close();
|
||||||
dir.close();
|
dir.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Tests sorting on multiple sort fields */
|
||||||
|
public void testMultiSort() throws IOException {
|
||||||
|
Directory dir = newDirectory();
|
||||||
|
RandomIndexWriter writer = new RandomIndexWriter(random(), dir);
|
||||||
|
Document doc = new Document();
|
||||||
|
doc.add(new SortedDocValuesField("value1", new BytesRef("foo")));
|
||||||
|
doc.add(new NumericDocValuesField("value2", 0));
|
||||||
|
doc.add(newStringField("value1", "foo", Field.Store.YES));
|
||||||
|
doc.add(newStringField("value2", "0", Field.Store.YES));
|
||||||
|
writer.addDocument(doc);
|
||||||
|
doc = new Document();
|
||||||
|
doc.add(new SortedDocValuesField("value1", new BytesRef("bar")));
|
||||||
|
doc.add(new NumericDocValuesField("value2", 1));
|
||||||
|
doc.add(newStringField("value1", "bar", Field.Store.YES));
|
||||||
|
doc.add(newStringField("value2", "1", Field.Store.YES));
|
||||||
|
writer.addDocument(doc);
|
||||||
|
doc = new Document();
|
||||||
|
doc.add(new SortedDocValuesField("value1", new BytesRef("bar")));
|
||||||
|
doc.add(new NumericDocValuesField("value2", 0));
|
||||||
|
doc.add(newStringField("value1", "bar", Field.Store.YES));
|
||||||
|
doc.add(newStringField("value2", "0", Field.Store.YES));
|
||||||
|
writer.addDocument(doc);
|
||||||
|
doc = new Document();
|
||||||
|
doc.add(new SortedDocValuesField("value1", new BytesRef("foo")));
|
||||||
|
doc.add(new NumericDocValuesField("value2", 1));
|
||||||
|
doc.add(newStringField("value1", "foo", Field.Store.YES));
|
||||||
|
doc.add(newStringField("value2", "1", Field.Store.YES));
|
||||||
|
writer.addDocument(doc);
|
||||||
|
IndexReader ir = writer.getReader();
|
||||||
|
writer.close();
|
||||||
|
|
||||||
|
IndexSearcher searcher = newSearcher(ir);
|
||||||
|
Sort sort = new Sort(
|
||||||
|
new SortField("value1", SortField.Type.STRING),
|
||||||
|
new SortField("value2", SortField.Type.LONG));
|
||||||
|
|
||||||
|
TopDocs td = searcher.search(new MatchAllDocsQuery(), 10, sort);
|
||||||
|
assertEquals(4, td.totalHits);
|
||||||
|
// 'bar' comes before 'foo'
|
||||||
|
assertEquals("bar", searcher.doc(td.scoreDocs[0].doc).get("value1"));
|
||||||
|
assertEquals("bar", searcher.doc(td.scoreDocs[1].doc).get("value1"));
|
||||||
|
assertEquals("foo", searcher.doc(td.scoreDocs[2].doc).get("value1"));
|
||||||
|
assertEquals("foo", searcher.doc(td.scoreDocs[3].doc).get("value1"));
|
||||||
|
// 0 comes before 1
|
||||||
|
assertEquals("0", searcher.doc(td.scoreDocs[0].doc).get("value2"));
|
||||||
|
assertEquals("1", searcher.doc(td.scoreDocs[1].doc).get("value2"));
|
||||||
|
assertEquals("0", searcher.doc(td.scoreDocs[2].doc).get("value2"));
|
||||||
|
assertEquals("1", searcher.doc(td.scoreDocs[3].doc).get("value2"));
|
||||||
|
|
||||||
|
// Now with overflow
|
||||||
|
td = searcher.search(new MatchAllDocsQuery(), 1, sort);
|
||||||
|
assertEquals(4, td.totalHits);
|
||||||
|
assertEquals("bar", searcher.doc(td.scoreDocs[0].doc).get("value1"));
|
||||||
|
assertEquals("0", searcher.doc(td.scoreDocs[0].doc).get("value2"));
|
||||||
|
|
||||||
|
ir.close();
|
||||||
|
dir.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@ public class TestTopDocsCollector extends LuceneTestCase {
|
||||||
private static final class MyTopsDocCollector extends TopDocsCollector<ScoreDoc> {
|
private static final class MyTopsDocCollector extends TopDocsCollector<ScoreDoc> {
|
||||||
|
|
||||||
private int idx = 0;
|
private int idx = 0;
|
||||||
private int base = 0;
|
|
||||||
|
|
||||||
public MyTopsDocCollector(int size) {
|
public MyTopsDocCollector(int size) {
|
||||||
super(new HitQueue(size, false));
|
super(new HitQueue(size, false));
|
||||||
|
@ -55,24 +54,26 @@ public class TestTopDocsCollector extends LuceneTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void collect(int doc) {
|
public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException {
|
||||||
++totalHits;
|
final int base = context.docBase;
|
||||||
pq.insertWithOverflow(new ScoreDoc(doc + base, scores[idx++]));
|
return new LeafCollector() {
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public void collect(int doc) {
|
||||||
|
++totalHits;
|
||||||
|
pq.insertWithOverflow(new ScoreDoc(doc + base, scores[idx++]));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doSetNextReader(LeafReaderContext context) throws IOException {
|
public void setScorer(Scorer scorer) {
|
||||||
base = context.docBase;
|
// Don't do anything. Assign scores in random
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setScorer(Scorer scorer) {
|
public boolean acceptsDocsOutOfOrder() {
|
||||||
// Don't do anything. Assign scores in random
|
return true;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
@Override
|
|
||||||
public boolean acceptsDocsOutOfOrder() {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,14 +171,14 @@ public class TestTopFieldCollector extends LuceneTestCase {
|
||||||
new boolean[] { true, true, true },
|
new boolean[] { true, true, true },
|
||||||
};
|
};
|
||||||
String[] actualTFCClasses = new String[] {
|
String[] actualTFCClasses = new String[] {
|
||||||
"OutOfOrderOneComparatorNonScoringCollector",
|
"OutOfOrderNonScoringCollector",
|
||||||
"OutOfOrderOneComparatorScoringMaxScoreCollector",
|
"OutOfOrderScoringMaxScoreCollector",
|
||||||
"OutOfOrderOneComparatorScoringNoMaxScoreCollector",
|
"OutOfOrderScoringNoMaxScoreCollector",
|
||||||
"OutOfOrderOneComparatorScoringMaxScoreCollector",
|
"OutOfOrderScoringMaxScoreCollector",
|
||||||
"OutOfOrderOneComparatorNonScoringCollector",
|
"OutOfOrderNonScoringCollector",
|
||||||
"OutOfOrderOneComparatorScoringMaxScoreCollector",
|
"OutOfOrderScoringMaxScoreCollector",
|
||||||
"OutOfOrderOneComparatorScoringNoMaxScoreCollector",
|
"OutOfOrderScoringNoMaxScoreCollector",
|
||||||
"OutOfOrderOneComparatorScoringMaxScoreCollector"
|
"OutOfOrderScoringMaxScoreCollector"
|
||||||
};
|
};
|
||||||
|
|
||||||
BooleanQuery bq = new BooleanQuery();
|
BooleanQuery bq = new BooleanQuery();
|
||||||
|
@ -220,14 +220,14 @@ public class TestTopFieldCollector extends LuceneTestCase {
|
||||||
new boolean[] { true, true, true },
|
new boolean[] { true, true, true },
|
||||||
};
|
};
|
||||||
String[] actualTFCClasses = new String[] {
|
String[] actualTFCClasses = new String[] {
|
||||||
"OutOfOrderMultiComparatorNonScoringCollector",
|
"OutOfOrderNonScoringCollector",
|
||||||
"OutOfOrderMultiComparatorScoringMaxScoreCollector",
|
"OutOfOrderScoringMaxScoreCollector",
|
||||||
"OutOfOrderMultiComparatorScoringNoMaxScoreCollector",
|
"OutOfOrderScoringNoMaxScoreCollector",
|
||||||
"OutOfOrderMultiComparatorScoringMaxScoreCollector",
|
"OutOfOrderScoringMaxScoreCollector",
|
||||||
"OutOfOrderMultiComparatorNonScoringCollector",
|
"OutOfOrderNonScoringCollector",
|
||||||
"OutOfOrderMultiComparatorScoringMaxScoreCollector",
|
"OutOfOrderScoringMaxScoreCollector",
|
||||||
"OutOfOrderMultiComparatorScoringNoMaxScoreCollector",
|
"OutOfOrderScoringNoMaxScoreCollector",
|
||||||
"OutOfOrderMultiComparatorScoringMaxScoreCollector"
|
"OutOfOrderScoringMaxScoreCollector"
|
||||||
};
|
};
|
||||||
|
|
||||||
BooleanQuery bq = new BooleanQuery();
|
BooleanQuery bq = new BooleanQuery();
|
||||||
|
|
|
@ -34,10 +34,6 @@ public class TestTopScoreDocCollector extends LuceneTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean[] inOrder = new boolean[] { false, true };
|
boolean[] inOrder = new boolean[] { false, true };
|
||||||
String[] actualTSDCClass = new String[] {
|
|
||||||
"OutOfOrderTopScoreDocCollector",
|
|
||||||
"InOrderTopScoreDocCollector"
|
|
||||||
};
|
|
||||||
|
|
||||||
BooleanQuery bq = new BooleanQuery();
|
BooleanQuery bq = new BooleanQuery();
|
||||||
// Add a Query with SHOULD, since bw.scorer() returns BooleanScorer2
|
// Add a Query with SHOULD, since bw.scorer() returns BooleanScorer2
|
||||||
|
@ -50,7 +46,8 @@ public class TestTopScoreDocCollector extends LuceneTestCase {
|
||||||
IndexSearcher searcher = newSearcher(reader);
|
IndexSearcher searcher = newSearcher(reader);
|
||||||
for (int i = 0; i < inOrder.length; i++) {
|
for (int i = 0; i < inOrder.length; i++) {
|
||||||
TopDocsCollector<ScoreDoc> tdc = TopScoreDocCollector.create(3, inOrder[i]);
|
TopDocsCollector<ScoreDoc> tdc = TopScoreDocCollector.create(3, inOrder[i]);
|
||||||
assertEquals("org.apache.lucene.search.TopScoreDocCollector$" + actualTSDCClass[i], tdc.getClass().getName());
|
LeafCollector leafCollector = tdc.getLeafCollector(reader.leaves().get(0));
|
||||||
|
assertEquals(!inOrder[i], leafCollector.acceptsDocsOutOfOrder());
|
||||||
|
|
||||||
searcher.search(new MatchAllDocsQuery(), tdc);
|
searcher.search(new MatchAllDocsQuery(), tdc);
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,11 @@ import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.queries.function.FunctionValues;
|
import org.apache.lucene.queries.function.FunctionValues;
|
||||||
import org.apache.lucene.queries.function.ValueSource;
|
import org.apache.lucene.queries.function.ValueSource;
|
||||||
import org.apache.lucene.search.FieldComparator;
|
import org.apache.lucene.search.FieldComparator;
|
||||||
|
import org.apache.lucene.search.LeafFieldComparator;
|
||||||
import org.apache.lucene.search.Scorer;
|
import org.apache.lucene.search.Scorer;
|
||||||
|
|
||||||
/** A custom comparator for sorting documents by an expression */
|
/** A custom comparator for sorting documents by an expression */
|
||||||
class ExpressionComparator extends FieldComparator<Double> {
|
class ExpressionComparator extends FieldComparator<Double> implements LeafFieldComparator {
|
||||||
private final double[] values;
|
private final double[] values;
|
||||||
private double bottom;
|
private double bottom;
|
||||||
private double topValue;
|
private double topValue;
|
||||||
|
@ -44,7 +45,6 @@ class ExpressionComparator extends FieldComparator<Double> {
|
||||||
// TODO: change FieldComparator.setScorer to throw IOException and remove this try-catch
|
// TODO: change FieldComparator.setScorer to throw IOException and remove this try-catch
|
||||||
@Override
|
@Override
|
||||||
public void setScorer(Scorer scorer) {
|
public void setScorer(Scorer scorer) {
|
||||||
super.setScorer(scorer);
|
|
||||||
// TODO: might be cleaner to lazy-init 'source' and set scorer after?
|
// TODO: might be cleaner to lazy-init 'source' and set scorer after?
|
||||||
assert readerContext != null;
|
assert readerContext != null;
|
||||||
try {
|
try {
|
||||||
|
@ -83,7 +83,7 @@ class ExpressionComparator extends FieldComparator<Double> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldComparator<Double> setNextReader(LeafReaderContext context) throws IOException {
|
public LeafFieldComparator getLeafComparator(LeafReaderContext context) throws IOException {
|
||||||
this.readerContext = context;
|
this.readerContext = context;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
|
||||||
|
|
||||||
private final Sort groupSort;
|
private final Sort groupSort;
|
||||||
private final FieldComparator<?>[] comparators;
|
private final FieldComparator<?>[] comparators;
|
||||||
|
private final LeafFieldComparator[] leafComparators;
|
||||||
private final int[] reversed;
|
private final int[] reversed;
|
||||||
private final int topNGroups;
|
private final int topNGroups;
|
||||||
private final HashMap<GROUP_VALUE_TYPE, CollectedSearchGroup<GROUP_VALUE_TYPE>> groupMap;
|
private final HashMap<GROUP_VALUE_TYPE, CollectedSearchGroup<GROUP_VALUE_TYPE>> groupMap;
|
||||||
|
@ -60,7 +61,6 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
|
||||||
* @param topNGroups How many top groups to keep.
|
* @param topNGroups How many top groups to keep.
|
||||||
* @throws IOException If I/O related errors occur
|
* @throws IOException If I/O related errors occur
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"unchecked","rawtypes"})
|
|
||||||
public AbstractFirstPassGroupingCollector(Sort groupSort, int topNGroups) throws IOException {
|
public AbstractFirstPassGroupingCollector(Sort groupSort, int topNGroups) throws IOException {
|
||||||
if (topNGroups < 1) {
|
if (topNGroups < 1) {
|
||||||
throw new IllegalArgumentException("topNGroups must be >= 1 (got " + topNGroups + ")");
|
throw new IllegalArgumentException("topNGroups must be >= 1 (got " + topNGroups + ")");
|
||||||
|
@ -74,6 +74,7 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
|
||||||
|
|
||||||
final SortField[] sortFields = groupSort.getSort();
|
final SortField[] sortFields = groupSort.getSort();
|
||||||
comparators = new FieldComparator[sortFields.length];
|
comparators = new FieldComparator[sortFields.length];
|
||||||
|
leafComparators = new LeafFieldComparator[sortFields.length];
|
||||||
compIDXEnd = comparators.length - 1;
|
compIDXEnd = comparators.length - 1;
|
||||||
reversed = new int[sortFields.length];
|
reversed = new int[sortFields.length];
|
||||||
for (int i = 0; i < sortFields.length; i++) {
|
for (int i = 0; i < sortFields.length; i++) {
|
||||||
|
@ -137,7 +138,7 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setScorer(Scorer scorer) throws IOException {
|
public void setScorer(Scorer scorer) throws IOException {
|
||||||
for (FieldComparator<?> comparator : comparators) {
|
for (LeafFieldComparator comparator : leafComparators) {
|
||||||
comparator.setScorer(scorer);
|
comparator.setScorer(scorer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,7 +158,7 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
|
||||||
// wasted effort as we will most likely be updating an existing group.
|
// wasted effort as we will most likely be updating an existing group.
|
||||||
if (orderedGroups != null) {
|
if (orderedGroups != null) {
|
||||||
for (int compIDX = 0;; compIDX++) {
|
for (int compIDX = 0;; compIDX++) {
|
||||||
final int c = reversed[compIDX] * comparators[compIDX].compareBottom(doc);
|
final int c = reversed[compIDX] * leafComparators[compIDX].compareBottom(doc);
|
||||||
if (c < 0) {
|
if (c < 0) {
|
||||||
// Definitely not competitive. So don't even bother to continue
|
// Definitely not competitive. So don't even bother to continue
|
||||||
return;
|
return;
|
||||||
|
@ -197,7 +198,7 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
|
||||||
sg.groupValue = copyDocGroupValue(groupValue, null);
|
sg.groupValue = copyDocGroupValue(groupValue, null);
|
||||||
sg.comparatorSlot = groupMap.size();
|
sg.comparatorSlot = groupMap.size();
|
||||||
sg.topDoc = docBase + doc;
|
sg.topDoc = docBase + doc;
|
||||||
for (FieldComparator<?> fc : comparators) {
|
for (LeafFieldComparator fc : leafComparators) {
|
||||||
fc.copy(sg.comparatorSlot, doc);
|
fc.copy(sg.comparatorSlot, doc);
|
||||||
}
|
}
|
||||||
groupMap.put(sg.groupValue, sg);
|
groupMap.put(sg.groupValue, sg);
|
||||||
|
@ -223,7 +224,7 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
|
||||||
bottomGroup.groupValue = copyDocGroupValue(groupValue, bottomGroup.groupValue);
|
bottomGroup.groupValue = copyDocGroupValue(groupValue, bottomGroup.groupValue);
|
||||||
bottomGroup.topDoc = docBase + doc;
|
bottomGroup.topDoc = docBase + doc;
|
||||||
|
|
||||||
for (FieldComparator<?> fc : comparators) {
|
for (LeafFieldComparator fc : leafComparators) {
|
||||||
fc.copy(bottomGroup.comparatorSlot, doc);
|
fc.copy(bottomGroup.comparatorSlot, doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +233,7 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
|
||||||
assert orderedGroups.size() == topNGroups;
|
assert orderedGroups.size() == topNGroups;
|
||||||
|
|
||||||
final int lastComparatorSlot = orderedGroups.last().comparatorSlot;
|
final int lastComparatorSlot = orderedGroups.last().comparatorSlot;
|
||||||
for (FieldComparator<?> fc : comparators) {
|
for (LeafFieldComparator fc : leafComparators) {
|
||||||
fc.setBottom(lastComparatorSlot);
|
fc.setBottom(lastComparatorSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,17 +242,16 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
|
||||||
|
|
||||||
// Update existing group:
|
// Update existing group:
|
||||||
for (int compIDX = 0;; compIDX++) {
|
for (int compIDX = 0;; compIDX++) {
|
||||||
final FieldComparator<?> fc = comparators[compIDX];
|
leafComparators[compIDX].copy(spareSlot, doc);
|
||||||
fc.copy(spareSlot, doc);
|
|
||||||
|
|
||||||
final int c = reversed[compIDX] * fc.compare(group.comparatorSlot, spareSlot);
|
final int c = reversed[compIDX] * comparators[compIDX].compare(group.comparatorSlot, spareSlot);
|
||||||
if (c < 0) {
|
if (c < 0) {
|
||||||
// Definitely not competitive.
|
// Definitely not competitive.
|
||||||
return;
|
return;
|
||||||
} else if (c > 0) {
|
} else if (c > 0) {
|
||||||
// Definitely competitive; set remaining comparators:
|
// Definitely competitive; set remaining comparators:
|
||||||
for (int compIDX2=compIDX+1; compIDX2<comparators.length; compIDX2++) {
|
for (int compIDX2=compIDX+1; compIDX2<comparators.length; compIDX2++) {
|
||||||
comparators[compIDX2].copy(spareSlot, doc);
|
leafComparators[compIDX2].copy(spareSlot, doc);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else if (compIDX == compIDXEnd) {
|
} else if (compIDX == compIDXEnd) {
|
||||||
|
@ -288,7 +288,7 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
|
||||||
final CollectedSearchGroup<?> newLast = orderedGroups.last();
|
final CollectedSearchGroup<?> newLast = orderedGroups.last();
|
||||||
// If we changed the value of the last group, or changed which group was last, then update bottom:
|
// If we changed the value of the last group, or changed which group was last, then update bottom:
|
||||||
if (group == newLast || prevLast != newLast) {
|
if (group == newLast || prevLast != newLast) {
|
||||||
for (FieldComparator<?> fc : comparators) {
|
for (LeafFieldComparator fc : leafComparators) {
|
||||||
fc.setBottom(newLast.comparatorSlot);
|
fc.setBottom(newLast.comparatorSlot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -315,7 +315,7 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
|
||||||
orderedGroups.addAll(groupMap.values());
|
orderedGroups.addAll(groupMap.values());
|
||||||
assert orderedGroups.size() > 0;
|
assert orderedGroups.size() > 0;
|
||||||
|
|
||||||
for (FieldComparator<?> fc : comparators) {
|
for (LeafFieldComparator fc : leafComparators) {
|
||||||
fc.setBottom(orderedGroups.last().comparatorSlot);
|
fc.setBottom(orderedGroups.last().comparatorSlot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -329,7 +329,7 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
|
||||||
protected void doSetNextReader(LeafReaderContext readerContext) throws IOException {
|
protected void doSetNextReader(LeafReaderContext readerContext) throws IOException {
|
||||||
docBase = readerContext.docBase;
|
docBase = readerContext.docBase;
|
||||||
for (int i=0; i<comparators.length; i++) {
|
for (int i=0; i<comparators.length; i++) {
|
||||||
comparators[i] = comparators[i].setNextReader(readerContext);
|
leafComparators[i] = comparators[i].getLeafComparator(readerContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ public abstract class AbstractSecondPassGroupingCollector<GROUP_VALUE_TYPE> exte
|
||||||
@Override
|
@Override
|
||||||
public void setScorer(Scorer scorer) throws IOException {
|
public void setScorer(Scorer scorer) throws IOException {
|
||||||
for (SearchGroupDocs<GROUP_VALUE_TYPE> group : groupMap.values()) {
|
for (SearchGroupDocs<GROUP_VALUE_TYPE> group : groupMap.values()) {
|
||||||
group.collector.setScorer(scorer);
|
group.leafCollector.setScorer(scorer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ public abstract class AbstractSecondPassGroupingCollector<GROUP_VALUE_TYPE> exte
|
||||||
SearchGroupDocs<GROUP_VALUE_TYPE> group = retrieveGroup(doc);
|
SearchGroupDocs<GROUP_VALUE_TYPE> group = retrieveGroup(doc);
|
||||||
if (group != null) {
|
if (group != null) {
|
||||||
totalGroupedHitCount++;
|
totalGroupedHitCount++;
|
||||||
group.collector.collect(doc);
|
group.leafCollector.collect(doc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ public abstract class AbstractSecondPassGroupingCollector<GROUP_VALUE_TYPE> exte
|
||||||
protected void doSetNextReader(LeafReaderContext readerContext) throws IOException {
|
protected void doSetNextReader(LeafReaderContext readerContext) throws IOException {
|
||||||
//System.out.println("SP.setNextReader");
|
//System.out.println("SP.setNextReader");
|
||||||
for (SearchGroupDocs<GROUP_VALUE_TYPE> group : groupMap.values()) {
|
for (SearchGroupDocs<GROUP_VALUE_TYPE> group : groupMap.values()) {
|
||||||
group.collector.getLeafCollector(readerContext);
|
group.leafCollector = group.collector.getLeafCollector(readerContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,6 +151,7 @@ public abstract class AbstractSecondPassGroupingCollector<GROUP_VALUE_TYPE> exte
|
||||||
|
|
||||||
public final GROUP_VALUE_TYPE groupValue;
|
public final GROUP_VALUE_TYPE groupValue;
|
||||||
public final TopDocsCollector<?> collector;
|
public final TopDocsCollector<?> collector;
|
||||||
|
public LeafCollector leafCollector;
|
||||||
|
|
||||||
public SearchGroupDocs(GROUP_VALUE_TYPE groupValue, TopDocsCollector<?> collector) {
|
public SearchGroupDocs(GROUP_VALUE_TYPE groupValue, TopDocsCollector<?> collector) {
|
||||||
this.groupValue = groupValue;
|
this.groupValue = groupValue;
|
||||||
|
|
|
@ -69,6 +69,7 @@ public class BlockGroupingCollector extends SimpleCollector {
|
||||||
private final boolean needsScores;
|
private final boolean needsScores;
|
||||||
|
|
||||||
private final FieldComparator<?>[] comparators;
|
private final FieldComparator<?>[] comparators;
|
||||||
|
private final LeafFieldComparator[] leafComparators;
|
||||||
private final int[] reversed;
|
private final int[] reversed;
|
||||||
private final int compIDXEnd;
|
private final int compIDXEnd;
|
||||||
private int bottomSlot;
|
private int bottomSlot;
|
||||||
|
@ -202,7 +203,7 @@ public class BlockGroupingCollector extends SimpleCollector {
|
||||||
bottomSlot = bottomGroup.comparatorSlot;
|
bottomSlot = bottomGroup.comparatorSlot;
|
||||||
//System.out.println(" set bottom=" + bottomSlot);
|
//System.out.println(" set bottom=" + bottomSlot);
|
||||||
for (int i = 0; i < comparators.length; i++) {
|
for (int i = 0; i < comparators.length; i++) {
|
||||||
comparators[i].setBottom(bottomSlot);
|
leafComparators[i].setBottom(bottomSlot);
|
||||||
}
|
}
|
||||||
//System.out.println(" QUEUE FULL");
|
//System.out.println(" QUEUE FULL");
|
||||||
} else {
|
} else {
|
||||||
|
@ -231,7 +232,7 @@ public class BlockGroupingCollector extends SimpleCollector {
|
||||||
|
|
||||||
//System.out.println(" set bottom=" + bottomSlot);
|
//System.out.println(" set bottom=" + bottomSlot);
|
||||||
for (int i = 0; i < comparators.length; i++) {
|
for (int i = 0; i < comparators.length; i++) {
|
||||||
comparators[i].setBottom(bottomSlot);
|
leafComparators[i].setBottom(bottomSlot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -278,6 +279,7 @@ public class BlockGroupingCollector extends SimpleCollector {
|
||||||
|
|
||||||
final SortField[] sortFields = groupSort.getSort();
|
final SortField[] sortFields = groupSort.getSort();
|
||||||
comparators = new FieldComparator<?>[sortFields.length];
|
comparators = new FieldComparator<?>[sortFields.length];
|
||||||
|
leafComparators = new LeafFieldComparator[sortFields.length];
|
||||||
compIDXEnd = comparators.length - 1;
|
compIDXEnd = comparators.length - 1;
|
||||||
reversed = new int[sortFields.length];
|
reversed = new int[sortFields.length];
|
||||||
for (int i = 0; i < sortFields.length; i++) {
|
for (int i = 0; i < sortFields.length; i++) {
|
||||||
|
@ -349,15 +351,15 @@ public class BlockGroupingCollector extends SimpleCollector {
|
||||||
collector = TopFieldCollector.create(withinGroupSort, maxDocsPerGroup, fillSortFields, needsScores, needsScores, true);
|
collector = TopFieldCollector.create(withinGroupSort, maxDocsPerGroup, fillSortFields, needsScores, needsScores, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
collector.setScorer(fakeScorer);
|
LeafCollector leafCollector = collector.getLeafCollector(og.readerContext);
|
||||||
collector.getLeafCollector(og.readerContext);
|
leafCollector.setScorer(fakeScorer);
|
||||||
for(int docIDX=0;docIDX<og.count;docIDX++) {
|
for(int docIDX=0;docIDX<og.count;docIDX++) {
|
||||||
final int doc = og.docs[docIDX];
|
final int doc = og.docs[docIDX];
|
||||||
fakeScorer.doc = doc;
|
fakeScorer.doc = doc;
|
||||||
if (needsScores) {
|
if (needsScores) {
|
||||||
fakeScorer.score = og.scores[docIDX];
|
fakeScorer.score = og.scores[docIDX];
|
||||||
}
|
}
|
||||||
collector.collect(doc);
|
leafCollector.collect(doc);
|
||||||
}
|
}
|
||||||
totalGroupedHitCount += og.count;
|
totalGroupedHitCount += og.count;
|
||||||
|
|
||||||
|
@ -402,7 +404,7 @@ public class BlockGroupingCollector extends SimpleCollector {
|
||||||
@Override
|
@Override
|
||||||
public void setScorer(Scorer scorer) throws IOException {
|
public void setScorer(Scorer scorer) throws IOException {
|
||||||
this.scorer = scorer;
|
this.scorer = scorer;
|
||||||
for (FieldComparator<?> comparator : comparators) {
|
for (LeafFieldComparator comparator : leafComparators) {
|
||||||
comparator.setScorer(scorer);
|
comparator.setScorer(scorer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,7 +445,7 @@ public class BlockGroupingCollector extends SimpleCollector {
|
||||||
assert !queueFull;
|
assert !queueFull;
|
||||||
|
|
||||||
//System.out.println(" init copy to bottomSlot=" + bottomSlot);
|
//System.out.println(" init copy to bottomSlot=" + bottomSlot);
|
||||||
for (FieldComparator<?> fc : comparators) {
|
for (LeafFieldComparator fc : leafComparators) {
|
||||||
fc.copy(bottomSlot, doc);
|
fc.copy(bottomSlot, doc);
|
||||||
fc.setBottom(bottomSlot);
|
fc.setBottom(bottomSlot);
|
||||||
}
|
}
|
||||||
|
@ -451,7 +453,7 @@ public class BlockGroupingCollector extends SimpleCollector {
|
||||||
} else {
|
} else {
|
||||||
// Compare to bottomSlot
|
// Compare to bottomSlot
|
||||||
for (int compIDX = 0;; compIDX++) {
|
for (int compIDX = 0;; compIDX++) {
|
||||||
final int c = reversed[compIDX] * comparators[compIDX].compareBottom(doc);
|
final int c = reversed[compIDX] * leafComparators[compIDX].compareBottom(doc);
|
||||||
if (c < 0) {
|
if (c < 0) {
|
||||||
// Definitely not competitive -- done
|
// Definitely not competitive -- done
|
||||||
return;
|
return;
|
||||||
|
@ -468,7 +470,7 @@ public class BlockGroupingCollector extends SimpleCollector {
|
||||||
|
|
||||||
//System.out.println(" best w/in group!");
|
//System.out.println(" best w/in group!");
|
||||||
|
|
||||||
for (FieldComparator<?> fc : comparators) {
|
for (LeafFieldComparator fc : leafComparators) {
|
||||||
fc.copy(bottomSlot, doc);
|
fc.copy(bottomSlot, doc);
|
||||||
// Necessary because some comparators cache
|
// Necessary because some comparators cache
|
||||||
// details of bottom slot; this forces them to
|
// details of bottom slot; this forces them to
|
||||||
|
@ -481,7 +483,7 @@ public class BlockGroupingCollector extends SimpleCollector {
|
||||||
// We're not sure this group will make it into the
|
// We're not sure this group will make it into the
|
||||||
// queue yet
|
// queue yet
|
||||||
for (int compIDX = 0;; compIDX++) {
|
for (int compIDX = 0;; compIDX++) {
|
||||||
final int c = reversed[compIDX] * comparators[compIDX].compareBottom(doc);
|
final int c = reversed[compIDX] * leafComparators[compIDX].compareBottom(doc);
|
||||||
if (c < 0) {
|
if (c < 0) {
|
||||||
// Definitely not competitive -- done
|
// Definitely not competitive -- done
|
||||||
//System.out.println(" doc doesn't compete w/ top groups");
|
//System.out.println(" doc doesn't compete w/ top groups");
|
||||||
|
@ -498,7 +500,7 @@ public class BlockGroupingCollector extends SimpleCollector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
groupCompetes = true;
|
groupCompetes = true;
|
||||||
for (FieldComparator<?> fc : comparators) {
|
for (LeafFieldComparator fc : leafComparators) {
|
||||||
fc.copy(bottomSlot, doc);
|
fc.copy(bottomSlot, doc);
|
||||||
// Necessary because some comparators cache
|
// Necessary because some comparators cache
|
||||||
// details of bottom slot; this forces them to
|
// details of bottom slot; this forces them to
|
||||||
|
@ -528,7 +530,7 @@ public class BlockGroupingCollector extends SimpleCollector {
|
||||||
|
|
||||||
currentReaderContext = readerContext;
|
currentReaderContext = readerContext;
|
||||||
for (int i=0; i<comparators.length; i++) {
|
for (int i=0; i<comparators.length; i++) {
|
||||||
comparators[i] = comparators[i].setNextReader(readerContext);
|
leafComparators[i] = comparators[i].getLeafComparator(readerContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package org.apache.lucene.search.grouping;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import org.apache.lucene.search.FieldComparator;
|
import org.apache.lucene.search.FieldComparator;
|
||||||
|
import org.apache.lucene.search.LeafFieldComparator;
|
||||||
import org.apache.lucene.search.Sort;
|
import org.apache.lucene.search.Sort;
|
||||||
import org.apache.lucene.search.SortField;
|
import org.apache.lucene.search.SortField;
|
||||||
|
|
||||||
|
@ -158,7 +159,7 @@ public class SearchGroup<GROUP_VALUE_TYPE> {
|
||||||
|
|
||||||
public GroupComparator(Sort groupSort) throws IOException {
|
public GroupComparator(Sort groupSort) throws IOException {
|
||||||
final SortField[] sortFields = groupSort.getSort();
|
final SortField[] sortFields = groupSort.getSort();
|
||||||
comparators = new FieldComparator<?>[sortFields.length];
|
comparators = new FieldComparator[sortFields.length];
|
||||||
reversed = new int[sortFields.length];
|
reversed = new int[sortFields.length];
|
||||||
for (int compIDX = 0; compIDX < sortFields.length; compIDX++) {
|
for (int compIDX = 0; compIDX < sortFields.length; compIDX++) {
|
||||||
final SortField sortField = sortFields[compIDX];
|
final SortField sortField = sortFields[compIDX];
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.queries.function.FunctionValues;
|
import org.apache.lucene.queries.function.FunctionValues;
|
||||||
import org.apache.lucene.queries.function.ValueSource;
|
import org.apache.lucene.queries.function.ValueSource;
|
||||||
import org.apache.lucene.search.FieldComparator;
|
import org.apache.lucene.search.FieldComparator;
|
||||||
|
import org.apache.lucene.search.LeafFieldComparator;
|
||||||
import org.apache.lucene.search.Scorer;
|
import org.apache.lucene.search.Scorer;
|
||||||
import org.apache.lucene.search.Sort;
|
import org.apache.lucene.search.Sort;
|
||||||
import org.apache.lucene.search.SortField;
|
import org.apache.lucene.search.SortField;
|
||||||
|
@ -94,7 +95,7 @@ public class FunctionAllGroupHeadsCollector extends AbstractAllGroupHeadsCollect
|
||||||
public void setScorer(Scorer scorer) throws IOException {
|
public void setScorer(Scorer scorer) throws IOException {
|
||||||
this.scorer = scorer;
|
this.scorer = scorer;
|
||||||
for (GroupHead groupHead : groups.values()) {
|
for (GroupHead groupHead : groups.values()) {
|
||||||
for (FieldComparator<?> comparator : groupHead.comparators) {
|
for (LeafFieldComparator comparator : groupHead.leafComparators) {
|
||||||
comparator.setScorer(scorer);
|
comparator.setScorer(scorer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,7 +110,7 @@ public class FunctionAllGroupHeadsCollector extends AbstractAllGroupHeadsCollect
|
||||||
|
|
||||||
for (GroupHead groupHead : groups.values()) {
|
for (GroupHead groupHead : groups.values()) {
|
||||||
for (int i = 0; i < groupHead.comparators.length; i++) {
|
for (int i = 0; i < groupHead.comparators.length; i++) {
|
||||||
groupHead.comparators[i] = groupHead.comparators[i].setNextReader(context);
|
groupHead.leafComparators[i] = groupHead.comparators[i].getLeafComparator(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,28 +121,31 @@ public class FunctionAllGroupHeadsCollector extends AbstractAllGroupHeadsCollect
|
||||||
public class GroupHead extends AbstractAllGroupHeadsCollector.GroupHead<MutableValue> {
|
public class GroupHead extends AbstractAllGroupHeadsCollector.GroupHead<MutableValue> {
|
||||||
|
|
||||||
final FieldComparator<?>[] comparators;
|
final FieldComparator<?>[] comparators;
|
||||||
|
final LeafFieldComparator[] leafComparators;
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked","rawtypes"})
|
@SuppressWarnings({"unchecked","rawtypes"})
|
||||||
private GroupHead(MutableValue groupValue, Sort sort, int doc) throws IOException {
|
private GroupHead(MutableValue groupValue, Sort sort, int doc) throws IOException {
|
||||||
super(groupValue, doc + readerContext.docBase);
|
super(groupValue, doc + readerContext.docBase);
|
||||||
final SortField[] sortFields = sort.getSort();
|
final SortField[] sortFields = sort.getSort();
|
||||||
comparators = new FieldComparator[sortFields.length];
|
comparators = new FieldComparator[sortFields.length];
|
||||||
|
leafComparators = new LeafFieldComparator[sortFields.length];
|
||||||
for (int i = 0; i < sortFields.length; i++) {
|
for (int i = 0; i < sortFields.length; i++) {
|
||||||
comparators[i] = sortFields[i].getComparator(1, i).setNextReader(readerContext);
|
comparators[i] = sortFields[i].getComparator(1, i);
|
||||||
comparators[i].setScorer(scorer);
|
leafComparators[i] = comparators[i].getLeafComparator(readerContext);
|
||||||
comparators[i].copy(0, doc);
|
leafComparators[i].setScorer(scorer);
|
||||||
comparators[i].setBottom(0);
|
leafComparators[i].copy(0, doc);
|
||||||
|
leafComparators[i].setBottom(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(int compIDX, int doc) throws IOException {
|
public int compare(int compIDX, int doc) throws IOException {
|
||||||
return comparators[compIDX].compareBottom(doc);
|
return leafComparators[compIDX].compareBottom(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateDocHead(int doc) throws IOException {
|
public void updateDocHead(int doc) throws IOException {
|
||||||
for (FieldComparator<?> comparator : comparators) {
|
for (LeafFieldComparator comparator : leafComparators) {
|
||||||
comparator.copy(0, doc);
|
comparator.copy(0, doc);
|
||||||
comparator.setBottom(0);
|
comparator.setBottom(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.index.DocValues;
|
import org.apache.lucene.index.DocValues;
|
||||||
import org.apache.lucene.index.SortedDocValues;
|
import org.apache.lucene.index.SortedDocValues;
|
||||||
import org.apache.lucene.search.FieldComparator;
|
import org.apache.lucene.search.FieldComparator;
|
||||||
|
import org.apache.lucene.search.LeafFieldComparator;
|
||||||
import org.apache.lucene.search.Scorer;
|
import org.apache.lucene.search.Scorer;
|
||||||
import org.apache.lucene.search.Sort;
|
import org.apache.lucene.search.Sort;
|
||||||
import org.apache.lucene.search.SortField;
|
import org.apache.lucene.search.SortField;
|
||||||
|
@ -164,7 +165,7 @@ public abstract class TermAllGroupHeadsCollector<GH extends AbstractAllGroupHead
|
||||||
|
|
||||||
for (GroupHead groupHead : groups.values()) {
|
for (GroupHead groupHead : groups.values()) {
|
||||||
for (int i = 0; i < groupHead.comparators.length; i++) {
|
for (int i = 0; i < groupHead.comparators.length; i++) {
|
||||||
groupHead.comparators[i] = groupHead.comparators[i].setNextReader(context);
|
groupHead.leafComparators[i] = groupHead.comparators[i].getLeafComparator(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,7 +174,7 @@ public abstract class TermAllGroupHeadsCollector<GH extends AbstractAllGroupHead
|
||||||
public void setScorer(Scorer scorer) throws IOException {
|
public void setScorer(Scorer scorer) throws IOException {
|
||||||
this.scorer = scorer;
|
this.scorer = scorer;
|
||||||
for (GroupHead groupHead : groups.values()) {
|
for (GroupHead groupHead : groups.values()) {
|
||||||
for (FieldComparator<?> comparator : groupHead.comparators) {
|
for (LeafFieldComparator comparator : groupHead.leafComparators) {
|
||||||
comparator.setScorer(scorer);
|
comparator.setScorer(scorer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,28 +182,31 @@ public abstract class TermAllGroupHeadsCollector<GH extends AbstractAllGroupHead
|
||||||
|
|
||||||
class GroupHead extends AbstractAllGroupHeadsCollector.GroupHead<BytesRef> {
|
class GroupHead extends AbstractAllGroupHeadsCollector.GroupHead<BytesRef> {
|
||||||
|
|
||||||
final FieldComparator<?>[] comparators;
|
final FieldComparator[] comparators;
|
||||||
|
final LeafFieldComparator[] leafComparators;
|
||||||
|
|
||||||
private GroupHead(BytesRef groupValue, Sort sort, int doc) throws IOException {
|
private GroupHead(BytesRef groupValue, Sort sort, int doc) throws IOException {
|
||||||
super(groupValue, doc + readerContext.docBase);
|
super(groupValue, doc + readerContext.docBase);
|
||||||
final SortField[] sortFields = sort.getSort();
|
final SortField[] sortFields = sort.getSort();
|
||||||
comparators = new FieldComparator[sortFields.length];
|
comparators = new FieldComparator[sortFields.length];
|
||||||
|
leafComparators = new LeafFieldComparator[sortFields.length];
|
||||||
for (int i = 0; i < sortFields.length; i++) {
|
for (int i = 0; i < sortFields.length; i++) {
|
||||||
comparators[i] = sortFields[i].getComparator(1, i).setNextReader(readerContext);
|
comparators[i] = sortFields[i].getComparator(1, i);
|
||||||
comparators[i].setScorer(scorer);
|
leafComparators[i] = comparators[i].getLeafComparator(readerContext);
|
||||||
comparators[i].copy(0, doc);
|
leafComparators[i].setScorer(scorer);
|
||||||
comparators[i].setBottom(0);
|
leafComparators[i].copy(0, doc);
|
||||||
|
leafComparators[i].setBottom(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(int compIDX, int doc) throws IOException {
|
public int compare(int compIDX, int doc) throws IOException {
|
||||||
return comparators[compIDX].compareBottom(doc);
|
return leafComparators[compIDX].compareBottom(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateDocHead(int doc) throws IOException {
|
public void updateDocHead(int doc) throws IOException {
|
||||||
for (FieldComparator<?> comparator : comparators) {
|
for (LeafFieldComparator comparator : leafComparators) {
|
||||||
comparator.copy(0, doc);
|
comparator.copy(0, doc);
|
||||||
comparator.setBottom(0);
|
comparator.setBottom(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ import java.util.*;
|
||||||
*
|
*
|
||||||
* @lucene.experimental
|
* @lucene.experimental
|
||||||
*/
|
*/
|
||||||
public class ToParentBlockJoinCollector extends SimpleCollector {
|
public class ToParentBlockJoinCollector implements Collector {
|
||||||
|
|
||||||
private final Sort sort;
|
private final Sort sort;
|
||||||
|
|
||||||
|
@ -83,16 +83,11 @@ public class ToParentBlockJoinCollector extends SimpleCollector {
|
||||||
private final Map<Query,Integer> joinQueryID = new HashMap<>();
|
private final Map<Query,Integer> joinQueryID = new HashMap<>();
|
||||||
private final int numParentHits;
|
private final int numParentHits;
|
||||||
private final FieldValueHitQueue<OneGroup> queue;
|
private final FieldValueHitQueue<OneGroup> queue;
|
||||||
private final FieldComparator[] comparators;
|
private final FieldComparator<?>[] comparators;
|
||||||
private final int[] reverseMul;
|
|
||||||
private final int compEnd;
|
|
||||||
private final boolean trackMaxScore;
|
private final boolean trackMaxScore;
|
||||||
private final boolean trackScores;
|
private final boolean trackScores;
|
||||||
|
|
||||||
private int docBase;
|
|
||||||
private ToParentBlockJoinQuery.BlockJoinScorer[] joinScorers = new ToParentBlockJoinQuery.BlockJoinScorer[0];
|
private ToParentBlockJoinQuery.BlockJoinScorer[] joinScorers = new ToParentBlockJoinQuery.BlockJoinScorer[0];
|
||||||
private LeafReaderContext currentReaderContext;
|
|
||||||
private Scorer scorer;
|
|
||||||
private boolean queueFull;
|
private boolean queueFull;
|
||||||
|
|
||||||
private OneGroup bottom;
|
private OneGroup bottom;
|
||||||
|
@ -116,8 +111,6 @@ public class ToParentBlockJoinCollector extends SimpleCollector {
|
||||||
this.numParentHits = numParentHits;
|
this.numParentHits = numParentHits;
|
||||||
queue = FieldValueHitQueue.create(sort.getSort(), numParentHits);
|
queue = FieldValueHitQueue.create(sort.getSort(), numParentHits);
|
||||||
comparators = queue.getComparators();
|
comparators = queue.getComparators();
|
||||||
reverseMul = queue.getReverseMul();
|
|
||||||
compEnd = comparators.length - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class OneGroup extends FieldValueHitQueue.Entry {
|
private static final class OneGroup extends FieldValueHitQueue.Entry {
|
||||||
|
@ -143,143 +136,172 @@ public class ToParentBlockJoinCollector extends SimpleCollector {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void collect(int parentDoc) throws IOException {
|
public LeafCollector getLeafCollector(final LeafReaderContext context)
|
||||||
//System.out.println("\nC parentDoc=" + parentDoc);
|
throws IOException {
|
||||||
totalHitCount++;
|
final LeafFieldComparator[] comparators = queue.getComparators(context);
|
||||||
|
final int[] reverseMul = queue.getReverseMul();
|
||||||
|
final int docBase = context.docBase;
|
||||||
|
return new LeafCollector() {
|
||||||
|
|
||||||
float score = Float.NaN;
|
private Scorer scorer;
|
||||||
|
|
||||||
if (trackMaxScore) {
|
@Override
|
||||||
score = scorer.score();
|
public void setScorer(Scorer scorer) throws IOException {
|
||||||
maxScore = Math.max(maxScore, score);
|
//System.out.println("C.setScorer scorer=" + scorer);
|
||||||
}
|
// Since we invoke .score(), and the comparators likely
|
||||||
|
// do as well, cache it so it's only "really" computed
|
||||||
// TODO: we could sweep all joinScorers here and
|
// once:
|
||||||
// aggregate total child hit count, so we can fill this
|
if (scorer instanceof ScoreCachingWrappingScorer == false) {
|
||||||
// in getTopGroups (we wire it to 0 now)
|
scorer = new ScoreCachingWrappingScorer(scorer);
|
||||||
|
|
||||||
if (queueFull) {
|
|
||||||
//System.out.println(" queueFull");
|
|
||||||
// Fastmatch: return if this hit is not competitive
|
|
||||||
for (int i = 0;; i++) {
|
|
||||||
final int c = reverseMul[i] * comparators[i].compareBottom(parentDoc);
|
|
||||||
if (c < 0) {
|
|
||||||
// Definitely not competitive.
|
|
||||||
//System.out.println(" skip");
|
|
||||||
return;
|
|
||||||
} else if (c > 0) {
|
|
||||||
// Definitely competitive.
|
|
||||||
break;
|
|
||||||
} else if (i == compEnd) {
|
|
||||||
// Here c=0. If we're at the last comparator, this doc is not
|
|
||||||
// competitive, since docs are visited in doc Id order, which means
|
|
||||||
// this doc cannot compete with any other document in the queue.
|
|
||||||
//System.out.println(" skip");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
this.scorer = scorer;
|
||||||
|
for (LeafFieldComparator comparator : comparators) {
|
||||||
//System.out.println(" competes! doc=" + (docBase + parentDoc));
|
comparator.setScorer(scorer);
|
||||||
|
|
||||||
// This hit is competitive - replace bottom element in queue & adjustTop
|
|
||||||
for (int i = 0; i < comparators.length; i++) {
|
|
||||||
comparators[i].copy(bottom.slot, parentDoc);
|
|
||||||
}
|
|
||||||
if (!trackMaxScore && trackScores) {
|
|
||||||
score = scorer.score();
|
|
||||||
}
|
|
||||||
bottom.doc = docBase + parentDoc;
|
|
||||||
bottom.readerContext = currentReaderContext;
|
|
||||||
bottom.score = score;
|
|
||||||
copyGroups(bottom);
|
|
||||||
bottom = queue.updateTop();
|
|
||||||
|
|
||||||
for (int i = 0; i < comparators.length; i++) {
|
|
||||||
comparators[i].setBottom(bottom.slot);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Startup transient: queue is not yet full:
|
|
||||||
final int comparatorSlot = totalHitCount - 1;
|
|
||||||
|
|
||||||
// Copy hit into queue
|
|
||||||
for (int i = 0; i < comparators.length; i++) {
|
|
||||||
comparators[i].copy(comparatorSlot, parentDoc);
|
|
||||||
}
|
|
||||||
//System.out.println(" startup: new OG doc=" + (docBase+parentDoc));
|
|
||||||
if (!trackMaxScore && trackScores) {
|
|
||||||
score = scorer.score();
|
|
||||||
}
|
|
||||||
final OneGroup og = new OneGroup(comparatorSlot, docBase+parentDoc, score, joinScorers.length, trackScores);
|
|
||||||
og.readerContext = currentReaderContext;
|
|
||||||
copyGroups(og);
|
|
||||||
bottom = queue.add(og);
|
|
||||||
queueFull = totalHitCount == numParentHits;
|
|
||||||
if (queueFull) {
|
|
||||||
// End of startup transient: queue just filled up:
|
|
||||||
for (int i = 0; i < comparators.length; i++) {
|
|
||||||
comparators[i].setBottom(bottom.slot);
|
|
||||||
}
|
}
|
||||||
}
|
Arrays.fill(joinScorers, null);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pulls out child doc and scores for all join queries:
|
Queue<Scorer> queue = new LinkedList<>();
|
||||||
private void copyGroups(OneGroup og) {
|
//System.out.println("\nqueue: add top scorer=" + scorer);
|
||||||
// While rare, it's possible top arrays could be too
|
queue.add(scorer);
|
||||||
// short if join query had null scorer on first
|
while ((scorer = queue.poll()) != null) {
|
||||||
// segment(s) but then became non-null on later segments
|
//System.out.println(" poll: " + scorer + "; " + scorer.getWeight().getQuery());
|
||||||
final int numSubScorers = joinScorers.length;
|
if (scorer instanceof ToParentBlockJoinQuery.BlockJoinScorer) {
|
||||||
if (og.docs.length < numSubScorers) {
|
enroll((ToParentBlockJoinQuery) scorer.getWeight().getQuery(), (ToParentBlockJoinQuery.BlockJoinScorer) scorer);
|
||||||
// While rare, this could happen if join query had
|
}
|
||||||
// null scorer on first segment(s) but then became
|
|
||||||
// non-null on later segments
|
for (ChildScorer sub : scorer.getChildren()) {
|
||||||
og.docs = ArrayUtil.grow(og.docs);
|
//System.out.println(" add sub: " + sub.child + "; " + sub.child.getWeight().getQuery());
|
||||||
}
|
queue.add(sub.child);
|
||||||
if (og.counts.length < numSubScorers) {
|
|
||||||
og.counts = ArrayUtil.grow(og.counts);
|
|
||||||
}
|
|
||||||
if (trackScores && og.scores.length < numSubScorers) {
|
|
||||||
og.scores = ArrayUtil.grow(og.scores);
|
|
||||||
}
|
|
||||||
|
|
||||||
//System.out.println("\ncopyGroups parentDoc=" + og.doc);
|
|
||||||
for(int scorerIDX = 0;scorerIDX < numSubScorers;scorerIDX++) {
|
|
||||||
final ToParentBlockJoinQuery.BlockJoinScorer joinScorer = joinScorers[scorerIDX];
|
|
||||||
//System.out.println(" scorer=" + joinScorer);
|
|
||||||
if (joinScorer != null && docBase + joinScorer.getParentDoc() == og.doc) {
|
|
||||||
og.counts[scorerIDX] = joinScorer.getChildCount();
|
|
||||||
//System.out.println(" count=" + og.counts[scorerIDX]);
|
|
||||||
og.docs[scorerIDX] = joinScorer.swapChildDocs(og.docs[scorerIDX]);
|
|
||||||
assert og.docs[scorerIDX].length >= og.counts[scorerIDX]: "length=" + og.docs[scorerIDX].length + " vs count=" + og.counts[scorerIDX];
|
|
||||||
//System.out.println(" len=" + og.docs[scorerIDX].length);
|
|
||||||
/*
|
|
||||||
for(int idx=0;idx<og.counts[scorerIDX];idx++) {
|
|
||||||
System.out.println(" docs[" + idx + "]=" + og.docs[scorerIDX][idx]);
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
if (trackScores) {
|
|
||||||
//System.out.println(" copy scores");
|
|
||||||
og.scores[scorerIDX] = joinScorer.swapChildScores(og.scores[scorerIDX]);
|
|
||||||
assert og.scores[scorerIDX].length >= og.counts[scorerIDX]: "length=" + og.scores[scorerIDX].length + " vs count=" + og.counts[scorerIDX];
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
og.counts[scorerIDX] = 0;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
@Override
|
||||||
|
public void collect(int parentDoc) throws IOException {
|
||||||
|
//System.out.println("\nC parentDoc=" + parentDoc);
|
||||||
|
totalHitCount++;
|
||||||
|
|
||||||
@Override
|
float score = Float.NaN;
|
||||||
protected void doSetNextReader(LeafReaderContext context) throws IOException {
|
|
||||||
currentReaderContext = context;
|
|
||||||
docBase = context.docBase;
|
|
||||||
for (int compIDX = 0; compIDX < comparators.length; compIDX++) {
|
|
||||||
queue.setComparator(compIDX, comparators[compIDX].setNextReader(context));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (trackMaxScore) {
|
||||||
public boolean acceptsDocsOutOfOrder() {
|
score = scorer.score();
|
||||||
return false;
|
maxScore = Math.max(maxScore, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: we could sweep all joinScorers here and
|
||||||
|
// aggregate total child hit count, so we can fill this
|
||||||
|
// in getTopGroups (we wire it to 0 now)
|
||||||
|
|
||||||
|
if (queueFull) {
|
||||||
|
//System.out.println(" queueFull");
|
||||||
|
// Fastmatch: return if this hit is not competitive
|
||||||
|
int c = 0;
|
||||||
|
for (int i = 0; i < comparators.length; ++i) {
|
||||||
|
c = reverseMul[i] * comparators[i].compareBottom(parentDoc);
|
||||||
|
if (c != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c <= 0) { // in case of equality, this hit is not competitive as docs are visited in order
|
||||||
|
// Definitely not competitive.
|
||||||
|
//System.out.println(" skip");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//System.out.println(" competes! doc=" + (docBase + parentDoc));
|
||||||
|
|
||||||
|
// This hit is competitive - replace bottom element in queue & adjustTop
|
||||||
|
for (LeafFieldComparator comparator : comparators) {
|
||||||
|
comparator.copy(bottom.slot, parentDoc);
|
||||||
|
}
|
||||||
|
if (!trackMaxScore && trackScores) {
|
||||||
|
score = scorer.score();
|
||||||
|
}
|
||||||
|
bottom.doc = docBase + parentDoc;
|
||||||
|
bottom.readerContext = context;
|
||||||
|
bottom.score = score;
|
||||||
|
copyGroups(bottom);
|
||||||
|
bottom = queue.updateTop();
|
||||||
|
|
||||||
|
for (LeafFieldComparator comparator : comparators) {
|
||||||
|
comparator.setBottom(bottom.slot);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Startup transient: queue is not yet full:
|
||||||
|
final int comparatorSlot = totalHitCount - 1;
|
||||||
|
|
||||||
|
// Copy hit into queue
|
||||||
|
for (LeafFieldComparator comparator : comparators) {
|
||||||
|
comparator.copy(comparatorSlot, parentDoc);
|
||||||
|
}
|
||||||
|
//System.out.println(" startup: new OG doc=" + (docBase+parentDoc));
|
||||||
|
if (!trackMaxScore && trackScores) {
|
||||||
|
score = scorer.score();
|
||||||
|
}
|
||||||
|
final OneGroup og = new OneGroup(comparatorSlot, docBase+parentDoc, score, joinScorers.length, trackScores);
|
||||||
|
og.readerContext = context;
|
||||||
|
copyGroups(og);
|
||||||
|
bottom = queue.add(og);
|
||||||
|
queueFull = totalHitCount == numParentHits;
|
||||||
|
if (queueFull) {
|
||||||
|
// End of startup transient: queue just filled up:
|
||||||
|
for (LeafFieldComparator comparator : comparators) {
|
||||||
|
comparator.setBottom(bottom.slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pulls out child doc and scores for all join queries:
|
||||||
|
private void copyGroups(OneGroup og) {
|
||||||
|
// While rare, it's possible top arrays could be too
|
||||||
|
// short if join query had null scorer on first
|
||||||
|
// segment(s) but then became non-null on later segments
|
||||||
|
final int numSubScorers = joinScorers.length;
|
||||||
|
if (og.docs.length < numSubScorers) {
|
||||||
|
// While rare, this could happen if join query had
|
||||||
|
// null scorer on first segment(s) but then became
|
||||||
|
// non-null on later segments
|
||||||
|
og.docs = ArrayUtil.grow(og.docs);
|
||||||
|
}
|
||||||
|
if (og.counts.length < numSubScorers) {
|
||||||
|
og.counts = ArrayUtil.grow(og.counts);
|
||||||
|
}
|
||||||
|
if (trackScores && og.scores.length < numSubScorers) {
|
||||||
|
og.scores = ArrayUtil.grow(og.scores);
|
||||||
|
}
|
||||||
|
|
||||||
|
//System.out.println("\ncopyGroups parentDoc=" + og.doc);
|
||||||
|
for(int scorerIDX = 0;scorerIDX < numSubScorers;scorerIDX++) {
|
||||||
|
final ToParentBlockJoinQuery.BlockJoinScorer joinScorer = joinScorers[scorerIDX];
|
||||||
|
//System.out.println(" scorer=" + joinScorer);
|
||||||
|
if (joinScorer != null && docBase + joinScorer.getParentDoc() == og.doc) {
|
||||||
|
og.counts[scorerIDX] = joinScorer.getChildCount();
|
||||||
|
//System.out.println(" count=" + og.counts[scorerIDX]);
|
||||||
|
og.docs[scorerIDX] = joinScorer.swapChildDocs(og.docs[scorerIDX]);
|
||||||
|
assert og.docs[scorerIDX].length >= og.counts[scorerIDX]: "length=" + og.docs[scorerIDX].length + " vs count=" + og.counts[scorerIDX];
|
||||||
|
//System.out.println(" len=" + og.docs[scorerIDX].length);
|
||||||
|
/*
|
||||||
|
for(int idx=0;idx<og.counts[scorerIDX];idx++) {
|
||||||
|
System.out.println(" docs[" + idx + "]=" + og.docs[scorerIDX][idx]);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (trackScores) {
|
||||||
|
//System.out.println(" copy scores");
|
||||||
|
og.scores[scorerIDX] = joinScorer.swapChildScores(og.scores[scorerIDX]);
|
||||||
|
assert og.scores[scorerIDX].length >= og.counts[scorerIDX]: "length=" + og.scores[scorerIDX].length + " vs count=" + og.counts[scorerIDX];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
og.counts[scorerIDX] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean acceptsDocsOutOfOrder() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enroll(ToParentBlockJoinQuery query, ToParentBlockJoinQuery.BlockJoinScorer scorer) {
|
private void enroll(ToParentBlockJoinQuery query, ToParentBlockJoinQuery.BlockJoinScorer scorer) {
|
||||||
|
@ -296,34 +318,6 @@ public class ToParentBlockJoinCollector extends SimpleCollector {
|
||||||
joinScorers[slot] = scorer;
|
joinScorers[slot] = scorer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setScorer(Scorer scorer) {
|
|
||||||
//System.out.println("C.setScorer scorer=" + scorer);
|
|
||||||
// Since we invoke .score(), and the comparators likely
|
|
||||||
// do as well, cache it so it's only "really" computed
|
|
||||||
// once:
|
|
||||||
this.scorer = new ScoreCachingWrappingScorer(scorer);
|
|
||||||
for (int compIDX = 0; compIDX < comparators.length; compIDX++) {
|
|
||||||
comparators[compIDX].setScorer(this.scorer);
|
|
||||||
}
|
|
||||||
Arrays.fill(joinScorers, null);
|
|
||||||
|
|
||||||
Queue<Scorer> queue = new LinkedList<>();
|
|
||||||
//System.out.println("\nqueue: add top scorer=" + scorer);
|
|
||||||
queue.add(scorer);
|
|
||||||
while ((scorer = queue.poll()) != null) {
|
|
||||||
//System.out.println(" poll: " + scorer + "; " + scorer.getWeight().getQuery());
|
|
||||||
if (scorer instanceof ToParentBlockJoinQuery.BlockJoinScorer) {
|
|
||||||
enroll((ToParentBlockJoinQuery) scorer.getWeight().getQuery(), (ToParentBlockJoinQuery.BlockJoinScorer) scorer);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ChildScorer sub : scorer.getChildren()) {
|
|
||||||
//System.out.println(" add sub: " + sub.child + "; " + sub.child.getWeight().getQuery());
|
|
||||||
queue.add(sub.child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private OneGroup[] sortedGroups;
|
private OneGroup[] sortedGroups;
|
||||||
|
|
||||||
|
@ -420,8 +414,8 @@ public class ToParentBlockJoinCollector extends SimpleCollector {
|
||||||
collector = TopFieldCollector.create(withinGroupSort, numDocsInGroup, fillSortFields, trackScores, trackMaxScore, true);
|
collector = TopFieldCollector.create(withinGroupSort, numDocsInGroup, fillSortFields, trackScores, trackMaxScore, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
collector.setScorer(fakeScorer);
|
LeafCollector leafCollector = collector.getLeafCollector(og.readerContext);
|
||||||
collector.getLeafCollector(og.readerContext);
|
leafCollector.setScorer(fakeScorer);
|
||||||
for(int docIDX=0;docIDX<numChildDocs;docIDX++) {
|
for(int docIDX=0;docIDX<numChildDocs;docIDX++) {
|
||||||
//System.out.println("docIDX=" + docIDX + " vs " + og.docs[slot].length);
|
//System.out.println("docIDX=" + docIDX + " vs " + og.docs[slot].length);
|
||||||
final int doc = og.docs[slot][docIDX];
|
final int doc = og.docs[slot][docIDX];
|
||||||
|
@ -429,7 +423,7 @@ public class ToParentBlockJoinCollector extends SimpleCollector {
|
||||||
if (trackScores) {
|
if (trackScores) {
|
||||||
fakeScorer.score = og.scores[slot][docIDX];
|
fakeScorer.score = og.scores[slot][docIDX];
|
||||||
}
|
}
|
||||||
collector.collect(doc);
|
leafCollector.collect(doc);
|
||||||
}
|
}
|
||||||
totalGroupedHitCount += numChildDocs;
|
totalGroupedHitCount += numChildDocs;
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@ import java.io.IOException;
|
||||||
import org.apache.lucene.index.LeafReaderContext;
|
import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.search.DocIdSetIterator;
|
import org.apache.lucene.search.DocIdSetIterator;
|
||||||
import org.apache.lucene.search.FieldComparator;
|
import org.apache.lucene.search.FieldComparator;
|
||||||
|
import org.apache.lucene.search.LeafFieldComparator;
|
||||||
|
import org.apache.lucene.search.SimpleFieldComparator;
|
||||||
import org.apache.lucene.util.BitDocIdSet;
|
import org.apache.lucene.util.BitDocIdSet;
|
||||||
import org.apache.lucene.util.BitSet;
|
import org.apache.lucene.util.BitSet;
|
||||||
|
|
||||||
|
@ -31,13 +33,14 @@ import org.apache.lucene.util.BitSet;
|
||||||
*
|
*
|
||||||
* @lucene.experimental
|
* @lucene.experimental
|
||||||
*/
|
*/
|
||||||
public abstract class ToParentBlockJoinFieldComparator extends FieldComparator<Object> {
|
public abstract class ToParentBlockJoinFieldComparator extends SimpleFieldComparator<Object> implements LeafFieldComparator { // repeat LeafFieldComparator for javadocs
|
||||||
|
|
||||||
private final BitDocIdSetFilter parentFilter;
|
private final BitDocIdSetFilter parentFilter;
|
||||||
private final BitDocIdSetFilter childFilter;
|
private final BitDocIdSetFilter childFilter;
|
||||||
final int spareSlot;
|
final int spareSlot;
|
||||||
|
|
||||||
FieldComparator<Object> wrappedComparator;
|
FieldComparator<Object> wrappedComparator;
|
||||||
|
LeafFieldComparator wrappedLeafComparator;
|
||||||
BitSet parentDocuments;
|
BitSet parentDocuments;
|
||||||
BitSet childDocuments;
|
BitSet childDocuments;
|
||||||
|
|
||||||
|
@ -55,7 +58,7 @@ public abstract class ToParentBlockJoinFieldComparator extends FieldComparator<O
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBottom(int slot) {
|
public void setBottom(int slot) {
|
||||||
wrappedComparator.setBottom(slot);
|
wrappedLeafComparator.setBottom(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -64,7 +67,7 @@ public abstract class ToParentBlockJoinFieldComparator extends FieldComparator<O
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldComparator<Object> setNextReader(LeafReaderContext context) throws IOException {
|
protected void doSetNextReader(LeafReaderContext context) throws IOException {
|
||||||
BitDocIdSet children = childFilter.getDocIdSet(context);
|
BitDocIdSet children = childFilter.getDocIdSet(context);
|
||||||
if (children == null) {
|
if (children == null) {
|
||||||
childDocuments = null;
|
childDocuments = null;
|
||||||
|
@ -77,8 +80,7 @@ public abstract class ToParentBlockJoinFieldComparator extends FieldComparator<O
|
||||||
} else {
|
} else {
|
||||||
parentDocuments = parents.bits();
|
parentDocuments = parents.bits();
|
||||||
}
|
}
|
||||||
wrappedComparator = wrappedComparator.setNextReader(context);
|
wrappedLeafComparator = wrappedComparator.getLeafComparator(context);
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -90,12 +92,12 @@ public abstract class ToParentBlockJoinFieldComparator extends FieldComparator<O
|
||||||
* Concrete implementation of {@link ToParentBlockJoinSortField} to sorts the parent docs with the lowest values
|
* Concrete implementation of {@link ToParentBlockJoinSortField} to sorts the parent docs with the lowest values
|
||||||
* in the child / nested docs first.
|
* in the child / nested docs first.
|
||||||
*/
|
*/
|
||||||
public static final class Lowest extends ToParentBlockJoinFieldComparator {
|
public static final class Lowest extends ToParentBlockJoinFieldComparator implements LeafFieldComparator {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create ToParentBlockJoinFieldComparator.Lowest
|
* Create ToParentBlockJoinFieldComparator.Lowest
|
||||||
*
|
*
|
||||||
* @param wrappedComparator The {@link FieldComparator} on the child / nested level.
|
* @param wrappedComparator The {@link LeafFieldComparator} on the child / nested level.
|
||||||
* @param parentFilter Filter that identifies the parent documents.
|
* @param parentFilter Filter that identifies the parent documents.
|
||||||
* @param childFilter Filter that defines which child / nested documents participates in sorting.
|
* @param childFilter Filter that defines which child / nested documents participates in sorting.
|
||||||
* @param spareSlot The extra slot inside the wrapped comparator that is used to compare which nested document
|
* @param spareSlot The extra slot inside the wrapped comparator that is used to compare which nested document
|
||||||
|
@ -119,7 +121,7 @@ public abstract class ToParentBlockJoinFieldComparator extends FieldComparator<O
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only need to emit a single cmp value for any matching child doc
|
// We only need to emit a single cmp value for any matching child doc
|
||||||
int cmp = wrappedComparator.compareBottom(childDoc);
|
int cmp = wrappedLeafComparator.compareBottom(childDoc);
|
||||||
if (cmp > 0) {
|
if (cmp > 0) {
|
||||||
return cmp;
|
return cmp;
|
||||||
}
|
}
|
||||||
|
@ -129,7 +131,7 @@ public abstract class ToParentBlockJoinFieldComparator extends FieldComparator<O
|
||||||
if (childDoc >= parentDoc || childDoc == DocIdSetIterator.NO_MORE_DOCS) {
|
if (childDoc >= parentDoc || childDoc == DocIdSetIterator.NO_MORE_DOCS) {
|
||||||
return cmp;
|
return cmp;
|
||||||
}
|
}
|
||||||
int cmp1 = wrappedComparator.compareBottom(childDoc);
|
int cmp1 = wrappedLeafComparator.compareBottom(childDoc);
|
||||||
if (cmp1 > 0) {
|
if (cmp1 > 0) {
|
||||||
return cmp1;
|
return cmp1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -152,23 +154,22 @@ public abstract class ToParentBlockJoinFieldComparator extends FieldComparator<O
|
||||||
if (childDoc >= parentDoc || childDoc == DocIdSetIterator.NO_MORE_DOCS) {
|
if (childDoc >= parentDoc || childDoc == DocIdSetIterator.NO_MORE_DOCS) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wrappedComparator.copy(spareSlot, childDoc);
|
wrappedLeafComparator.copy(spareSlot, childDoc);
|
||||||
wrappedComparator.copy(slot, childDoc);
|
wrappedLeafComparator.copy(slot, childDoc);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
childDoc = childDocuments.nextSetBit(childDoc + 1);
|
childDoc = childDocuments.nextSetBit(childDoc + 1);
|
||||||
if (childDoc >= parentDoc || childDoc == DocIdSetIterator.NO_MORE_DOCS) {
|
if (childDoc >= parentDoc || childDoc == DocIdSetIterator.NO_MORE_DOCS) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wrappedComparator.copy(spareSlot, childDoc);
|
wrappedLeafComparator.copy(spareSlot, childDoc);
|
||||||
if (wrappedComparator.compare(spareSlot, slot) < 0) {
|
if (wrappedComparator.compare(spareSlot, slot) < 0) {
|
||||||
wrappedComparator.copy(slot, childDoc);
|
wrappedLeafComparator.copy(slot, childDoc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public int compareTop(int parentDoc) throws IOException {
|
public int compareTop(int parentDoc) throws IOException {
|
||||||
if (parentDoc == 0 || parentDocuments == null || childDocuments == null) {
|
if (parentDoc == 0 || parentDocuments == null || childDocuments == null) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -182,7 +183,7 @@ public abstract class ToParentBlockJoinFieldComparator extends FieldComparator<O
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only need to emit a single cmp value for any matching child doc
|
// We only need to emit a single cmp value for any matching child doc
|
||||||
int cmp = wrappedComparator.compareBottom(childDoc);
|
int cmp = wrappedLeafComparator.compareBottom(childDoc);
|
||||||
if (cmp > 0) {
|
if (cmp > 0) {
|
||||||
return cmp;
|
return cmp;
|
||||||
}
|
}
|
||||||
|
@ -192,7 +193,7 @@ public abstract class ToParentBlockJoinFieldComparator extends FieldComparator<O
|
||||||
if (childDoc >= parentDoc || childDoc == DocIdSetIterator.NO_MORE_DOCS) {
|
if (childDoc >= parentDoc || childDoc == DocIdSetIterator.NO_MORE_DOCS) {
|
||||||
return cmp;
|
return cmp;
|
||||||
}
|
}
|
||||||
int cmp1 = wrappedComparator.compareTop(childDoc);
|
int cmp1 = wrappedLeafComparator.compareTop(childDoc);
|
||||||
if (cmp1 > 0) {
|
if (cmp1 > 0) {
|
||||||
return cmp1;
|
return cmp1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -209,12 +210,12 @@ public abstract class ToParentBlockJoinFieldComparator extends FieldComparator<O
|
||||||
* Concrete implementation of {@link ToParentBlockJoinSortField} to sorts the parent docs with the highest values
|
* Concrete implementation of {@link ToParentBlockJoinSortField} to sorts the parent docs with the highest values
|
||||||
* in the child / nested docs first.
|
* in the child / nested docs first.
|
||||||
*/
|
*/
|
||||||
public static final class Highest extends ToParentBlockJoinFieldComparator {
|
public static final class Highest extends ToParentBlockJoinFieldComparator implements LeafFieldComparator {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create ToParentBlockJoinFieldComparator.Highest
|
* Create ToParentBlockJoinFieldComparator.Highest
|
||||||
*
|
*
|
||||||
* @param wrappedComparator The {@link FieldComparator} on the child / nested level.
|
* @param wrappedComparator The {@link LeafFieldComparator} on the child / nested level.
|
||||||
* @param parentFilter Filter that identifies the parent documents.
|
* @param parentFilter Filter that identifies the parent documents.
|
||||||
* @param childFilter Filter that defines which child / nested documents participates in sorting.
|
* @param childFilter Filter that defines which child / nested documents participates in sorting.
|
||||||
* @param spareSlot The extra slot inside the wrapped comparator that is used to compare which nested document
|
* @param spareSlot The extra slot inside the wrapped comparator that is used to compare which nested document
|
||||||
|
@ -236,7 +237,7 @@ public abstract class ToParentBlockJoinFieldComparator extends FieldComparator<O
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmp = wrappedComparator.compareBottom(childDoc);
|
int cmp = wrappedLeafComparator.compareBottom(childDoc);
|
||||||
if (cmp < 0) {
|
if (cmp < 0) {
|
||||||
return cmp;
|
return cmp;
|
||||||
}
|
}
|
||||||
|
@ -246,7 +247,7 @@ public abstract class ToParentBlockJoinFieldComparator extends FieldComparator<O
|
||||||
if (childDoc >= parentDoc || childDoc == DocIdSetIterator.NO_MORE_DOCS) {
|
if (childDoc >= parentDoc || childDoc == DocIdSetIterator.NO_MORE_DOCS) {
|
||||||
return cmp;
|
return cmp;
|
||||||
}
|
}
|
||||||
int cmp1 = wrappedComparator.compareBottom(childDoc);
|
int cmp1 = wrappedLeafComparator.compareBottom(childDoc);
|
||||||
if (cmp1 < 0) {
|
if (cmp1 < 0) {
|
||||||
return cmp1;
|
return cmp1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -268,23 +269,22 @@ public abstract class ToParentBlockJoinFieldComparator extends FieldComparator<O
|
||||||
if (childDoc >= parentDoc || childDoc == DocIdSetIterator.NO_MORE_DOCS) {
|
if (childDoc >= parentDoc || childDoc == DocIdSetIterator.NO_MORE_DOCS) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wrappedComparator.copy(spareSlot, childDoc);
|
wrappedLeafComparator.copy(spareSlot, childDoc);
|
||||||
wrappedComparator.copy(slot, childDoc);
|
wrappedLeafComparator.copy(slot, childDoc);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
childDoc = childDocuments.nextSetBit(childDoc + 1);
|
childDoc = childDocuments.nextSetBit(childDoc + 1);
|
||||||
if (childDoc >= parentDoc || childDoc == DocIdSetIterator.NO_MORE_DOCS) {
|
if (childDoc >= parentDoc || childDoc == DocIdSetIterator.NO_MORE_DOCS) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wrappedComparator.copy(spareSlot, childDoc);
|
wrappedLeafComparator.copy(spareSlot, childDoc);
|
||||||
if (wrappedComparator.compare(spareSlot, slot) > 0) {
|
if (wrappedComparator.compare(spareSlot, slot) > 0) {
|
||||||
wrappedComparator.copy(slot, childDoc);
|
wrappedLeafComparator.copy(slot, childDoc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public int compareTop(int parentDoc) throws IOException {
|
public int compareTop(int parentDoc) throws IOException {
|
||||||
if (parentDoc == 0 || parentDocuments == null || childDocuments == null) {
|
if (parentDoc == 0 || parentDocuments == null || childDocuments == null) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -296,7 +296,7 @@ public abstract class ToParentBlockJoinFieldComparator extends FieldComparator<O
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmp = wrappedComparator.compareBottom(childDoc);
|
int cmp = wrappedLeafComparator.compareBottom(childDoc);
|
||||||
if (cmp < 0) {
|
if (cmp < 0) {
|
||||||
return cmp;
|
return cmp;
|
||||||
}
|
}
|
||||||
|
@ -306,7 +306,7 @@ public abstract class ToParentBlockJoinFieldComparator extends FieldComparator<O
|
||||||
if (childDoc >= parentDoc || childDoc == DocIdSetIterator.NO_MORE_DOCS) {
|
if (childDoc >= parentDoc || childDoc == DocIdSetIterator.NO_MORE_DOCS) {
|
||||||
return cmp;
|
return cmp;
|
||||||
}
|
}
|
||||||
int cmp1 = wrappedComparator.compareTop(childDoc);
|
int cmp1 = wrappedLeafComparator.compareTop(childDoc);
|
||||||
if (cmp1 < 0) {
|
if (cmp1 < 0) {
|
||||||
return cmp1;
|
return cmp1;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -18,6 +18,7 @@ package org.apache.lucene.search.join;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import org.apache.lucene.search.FieldComparator;
|
import org.apache.lucene.search.FieldComparator;
|
||||||
|
import org.apache.lucene.search.LeafFieldComparator;
|
||||||
import org.apache.lucene.search.SortField;
|
import org.apache.lucene.search.SortField;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
|
@ -52,9 +52,12 @@ import org.apache.lucene.index.Terms;
|
||||||
import org.apache.lucene.index.TermsEnum;
|
import org.apache.lucene.index.TermsEnum;
|
||||||
import org.apache.lucene.search.BooleanClause;
|
import org.apache.lucene.search.BooleanClause;
|
||||||
import org.apache.lucene.search.BooleanQuery;
|
import org.apache.lucene.search.BooleanQuery;
|
||||||
|
import org.apache.lucene.search.Collector;
|
||||||
import org.apache.lucene.search.DocIdSetIterator;
|
import org.apache.lucene.search.DocIdSetIterator;
|
||||||
import org.apache.lucene.search.Explanation;
|
import org.apache.lucene.search.Explanation;
|
||||||
|
import org.apache.lucene.search.FilterLeafCollector;
|
||||||
import org.apache.lucene.search.IndexSearcher;
|
import org.apache.lucene.search.IndexSearcher;
|
||||||
|
import org.apache.lucene.search.LeafCollector;
|
||||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
import org.apache.lucene.search.ScoreDoc;
|
import org.apache.lucene.search.ScoreDoc;
|
||||||
|
@ -482,30 +485,25 @@ public class TestJoinUtil extends LuceneTestCase {
|
||||||
// Need to know all documents that have matches. TopDocs doesn't give me that and then I'd be also testing TopDocsCollector...
|
// Need to know all documents that have matches. TopDocs doesn't give me that and then I'd be also testing TopDocsCollector...
|
||||||
final BitSet actualResult = new FixedBitSet(indexSearcher.getIndexReader().maxDoc());
|
final BitSet actualResult = new FixedBitSet(indexSearcher.getIndexReader().maxDoc());
|
||||||
final TopScoreDocCollector topScoreDocCollector = TopScoreDocCollector.create(10, false);
|
final TopScoreDocCollector topScoreDocCollector = TopScoreDocCollector.create(10, false);
|
||||||
indexSearcher.search(joinQuery, new SimpleCollector() {
|
indexSearcher.search(joinQuery, new Collector() {
|
||||||
|
|
||||||
int docBase;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void collect(int doc) throws IOException {
|
public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException {
|
||||||
actualResult.set(doc + docBase);
|
final int docBase = context.docBase;
|
||||||
topScoreDocCollector.collect(doc);
|
final LeafCollector in = topScoreDocCollector.getLeafCollector(context);
|
||||||
}
|
return new FilterLeafCollector(in) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doSetNextReader(LeafReaderContext context) throws IOException {
|
public void collect(int doc) throws IOException {
|
||||||
docBase = context.docBase;
|
super.collect(doc);
|
||||||
topScoreDocCollector.getLeafCollector(context);
|
actualResult.set(doc + docBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setScorer(Scorer scorer) throws IOException {
|
public boolean acceptsDocsOutOfOrder() {
|
||||||
topScoreDocCollector.setScorer(scorer);
|
return scoreDocsInOrder;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
@Override
|
|
||||||
public boolean acceptsDocsOutOfOrder() {
|
|
||||||
return scoreDocsInOrder;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Asserting bit set...
|
// Asserting bit set...
|
||||||
|
|
|
@ -20,9 +20,7 @@ package org.apache.lucene.index;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
import org.apache.lucene.index.LeafReader;
|
import org.apache.lucene.search.LeafFieldComparator;
|
||||||
import org.apache.lucene.index.IndexReader;
|
|
||||||
import org.apache.lucene.search.FieldComparator;
|
|
||||||
import org.apache.lucene.search.Scorer;
|
import org.apache.lucene.search.Scorer;
|
||||||
import org.apache.lucene.search.Sort;
|
import org.apache.lucene.search.Sort;
|
||||||
import org.apache.lucene.search.SortField;
|
import org.apache.lucene.search.SortField;
|
||||||
|
@ -214,12 +212,11 @@ final class Sorter {
|
||||||
DocMap sort(LeafReader reader) throws IOException {
|
DocMap sort(LeafReader reader) throws IOException {
|
||||||
SortField fields[] = sort.getSort();
|
SortField fields[] = sort.getSort();
|
||||||
final int reverseMul[] = new int[fields.length];
|
final int reverseMul[] = new int[fields.length];
|
||||||
final FieldComparator<?> comparators[] = new FieldComparator[fields.length];
|
final LeafFieldComparator comparators[] = new LeafFieldComparator[fields.length];
|
||||||
|
|
||||||
for (int i = 0; i < fields.length; i++) {
|
for (int i = 0; i < fields.length; i++) {
|
||||||
reverseMul[i] = fields[i].getReverse() ? -1 : 1;
|
reverseMul[i] = fields[i].getReverse() ? -1 : 1;
|
||||||
comparators[i] = fields[i].getComparator(1, i);
|
comparators[i] = fields[i].getComparator(1, i).getLeafComparator(reader.getContext());
|
||||||
comparators[i].setNextReader(reader.getContext());
|
|
||||||
comparators[i].setScorer(FAKESCORER);
|
comparators[i].setScorer(FAKESCORER);
|
||||||
}
|
}
|
||||||
final DocComparator comparator = new DocComparator() {
|
final DocComparator comparator = new DocComparator() {
|
||||||
|
|
|
@ -21,18 +21,8 @@ import java.io.IOException;
|
||||||
|
|
||||||
import org.apache.lucene.index.LeafReaderContext;
|
import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.index.SortingMergePolicy;
|
import org.apache.lucene.index.SortingMergePolicy;
|
||||||
import org.apache.lucene.search.DocIdSet;
|
|
||||||
import org.apache.lucene.search.FieldComparator;
|
|
||||||
import org.apache.lucene.search.FieldComparatorSource;
|
|
||||||
import org.apache.lucene.search.Filter;
|
|
||||||
import org.apache.lucene.search.IndexSearcher; // javadocs
|
|
||||||
import org.apache.lucene.search.Query; // javadocs
|
|
||||||
import org.apache.lucene.search.ScoreDoc; // javadocs
|
|
||||||
import org.apache.lucene.search.Scorer;
|
|
||||||
import org.apache.lucene.search.Sort;
|
|
||||||
import org.apache.lucene.search.SortField;
|
|
||||||
import org.apache.lucene.util.BitDocIdSet;
|
import org.apache.lucene.util.BitDocIdSet;
|
||||||
import org.apache.lucene.util.FixedBitSet;
|
import org.apache.lucene.util.BitSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class to sort readers that contain blocks of documents.
|
* Helper class to sort readers that contain blocks of documents.
|
||||||
|
@ -51,22 +41,22 @@ public class BlockJoinComparatorSource extends FieldComparatorSource {
|
||||||
final Filter parentsFilter;
|
final Filter parentsFilter;
|
||||||
final Sort parentSort;
|
final Sort parentSort;
|
||||||
final Sort childSort;
|
final Sort childSort;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new BlockJoinComparatorSource, sorting only blocks of documents
|
* Create a new BlockJoinComparatorSource, sorting only blocks of documents
|
||||||
* with {@code parentSort} and not reordering children with a block.
|
* with {@code parentSort} and not reordering children with a block.
|
||||||
*
|
*
|
||||||
* @param parentsFilter Filter identifying parent documents
|
* @param parentsFilter Filter identifying parent documents
|
||||||
* @param parentSort Sort for parent documents
|
* @param parentSort Sort for parent documents
|
||||||
*/
|
*/
|
||||||
public BlockJoinComparatorSource(Filter parentsFilter, Sort parentSort) {
|
public BlockJoinComparatorSource(Filter parentsFilter, Sort parentSort) {
|
||||||
this(parentsFilter, parentSort, new Sort(SortField.FIELD_DOC));
|
this(parentsFilter, parentSort, new Sort(SortField.FIELD_DOC));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new BlockJoinComparatorSource, specifying the sort order for both
|
* Create a new BlockJoinComparatorSource, specifying the sort order for both
|
||||||
* blocks of documents and children within a block.
|
* blocks of documents and children within a block.
|
||||||
*
|
*
|
||||||
* @param parentsFilter Filter identifying parent documents
|
* @param parentsFilter Filter identifying parent documents
|
||||||
* @param parentSort Sort for parent documents
|
* @param parentSort Sort for parent documents
|
||||||
* @param childSort Sort for child documents in the same block
|
* @param childSort Sort for child documents in the same block
|
||||||
|
@ -82,7 +72,7 @@ public class BlockJoinComparatorSource extends FieldComparatorSource {
|
||||||
// we keep parallel slots: the parent ids and the child ids
|
// we keep parallel slots: the parent ids and the child ids
|
||||||
final int parentSlots[] = new int[numHits];
|
final int parentSlots[] = new int[numHits];
|
||||||
final int childSlots[] = new int[numHits];
|
final int childSlots[] = new int[numHits];
|
||||||
|
|
||||||
SortField parentFields[] = parentSort.getSort();
|
SortField parentFields[] = parentSort.getSort();
|
||||||
final int parentReverseMul[] = new int[parentFields.length];
|
final int parentReverseMul[] = new int[parentFields.length];
|
||||||
final FieldComparator<?> parentComparators[] = new FieldComparator[parentFields.length];
|
final FieldComparator<?> parentComparators[] = new FieldComparator[parentFields.length];
|
||||||
|
@ -90,7 +80,7 @@ public class BlockJoinComparatorSource extends FieldComparatorSource {
|
||||||
parentReverseMul[i] = parentFields[i].getReverse() ? -1 : 1;
|
parentReverseMul[i] = parentFields[i].getReverse() ? -1 : 1;
|
||||||
parentComparators[i] = parentFields[i].getComparator(1, i);
|
parentComparators[i] = parentFields[i].getComparator(1, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
SortField childFields[] = childSort.getSort();
|
SortField childFields[] = childSort.getSort();
|
||||||
final int childReverseMul[] = new int[childFields.length];
|
final int childReverseMul[] = new int[childFields.length];
|
||||||
final FieldComparator<?> childComparators[] = new FieldComparator[childFields.length];
|
final FieldComparator<?> childComparators[] = new FieldComparator[childFields.length];
|
||||||
|
@ -98,14 +88,16 @@ public class BlockJoinComparatorSource extends FieldComparatorSource {
|
||||||
childReverseMul[i] = childFields[i].getReverse() ? -1 : 1;
|
childReverseMul[i] = childFields[i].getReverse() ? -1 : 1;
|
||||||
childComparators[i] = childFields[i].getComparator(1, i);
|
childComparators[i] = childFields[i].getComparator(1, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: we could return parent ID as value but really our sort "value" is more complex...
|
// NOTE: we could return parent ID as value but really our sort "value" is more complex...
|
||||||
// So we throw UOE for now. At the moment you really should only use this at indexing time.
|
// So we throw UOE for now. At the moment you really should only use this at indexing time.
|
||||||
return new FieldComparator<Integer>() {
|
return new FieldComparator<Integer>() {
|
||||||
int bottomParent;
|
int bottomParent;
|
||||||
int bottomChild;
|
int bottomChild;
|
||||||
FixedBitSet parentBits;
|
BitSet parentBits;
|
||||||
|
LeafFieldComparator[] parentLeafComparators;
|
||||||
|
LeafFieldComparator[] childLeafComparators;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(int slot1, int slot2) {
|
public int compare(int slot1, int slot2) {
|
||||||
try {
|
try {
|
||||||
|
@ -115,12 +107,6 @@ public class BlockJoinComparatorSource extends FieldComparatorSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBottom(int slot) {
|
|
||||||
bottomParent = parentSlots[slot];
|
|
||||||
bottomChild = childSlots[slot];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTopValue(Integer value) {
|
public void setTopValue(Integer value) {
|
||||||
// we dont have enough information (the docid is needed)
|
// we dont have enough information (the docid is needed)
|
||||||
|
@ -128,39 +114,63 @@ public class BlockJoinComparatorSource extends FieldComparatorSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareBottom(int doc) throws IOException {
|
public LeafFieldComparator getLeafComparator(LeafReaderContext context) throws IOException {
|
||||||
return compare(bottomChild, bottomParent, doc, parent(doc));
|
if (parentBits != null) {
|
||||||
}
|
throw new IllegalStateException("This comparator can only be used on a single segment");
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public int compareTop(int doc) throws IOException {
|
|
||||||
// we dont have enough information (the docid is needed)
|
|
||||||
throw new UnsupportedOperationException("this comparator cannot be used with deep paging");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void copy(int slot, int doc) throws IOException {
|
|
||||||
childSlots[slot] = doc;
|
|
||||||
parentSlots[slot] = parent(doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FieldComparator<Integer> setNextReader(LeafReaderContext context) throws IOException {
|
|
||||||
final DocIdSet parents = parentsFilter.getDocIdSet(context, null);
|
final DocIdSet parents = parentsFilter.getDocIdSet(context, null);
|
||||||
if (parents == null) {
|
if (parents == null) {
|
||||||
throw new IllegalStateException("LeafReader " + context.reader() + " contains no parents!");
|
throw new IllegalStateException("LeafReader " + context.reader() + " contains no parents!");
|
||||||
}
|
}
|
||||||
if (!(parents instanceof BitDocIdSet)) {
|
if (parents instanceof BitDocIdSet == false) {
|
||||||
throw new IllegalStateException("parentFilter must return FixedBitSet; got " + parents);
|
throw new IllegalStateException("parentFilter must return BitSet; got " + parents);
|
||||||
}
|
}
|
||||||
parentBits = (FixedBitSet) parents.bits();
|
parentBits = (BitSet) parents.bits();
|
||||||
|
parentLeafComparators = new LeafFieldComparator[parentComparators.length];
|
||||||
for (int i = 0; i < parentComparators.length; i++) {
|
for (int i = 0; i < parentComparators.length; i++) {
|
||||||
parentComparators[i] = parentComparators[i].setNextReader(context);
|
parentLeafComparators[i] = parentComparators[i].getLeafComparator(context);
|
||||||
}
|
}
|
||||||
|
childLeafComparators = new LeafFieldComparator[childComparators.length];
|
||||||
for (int i = 0; i < childComparators.length; i++) {
|
for (int i = 0; i < childComparators.length; i++) {
|
||||||
childComparators[i] = childComparators[i].setNextReader(context);
|
childLeafComparators[i] = childComparators[i].getLeafComparator(context);
|
||||||
}
|
}
|
||||||
return this;
|
|
||||||
|
return new LeafFieldComparator() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareBottom(int doc) throws IOException {
|
||||||
|
return compare(bottomChild, bottomParent, doc, parent(doc));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTop(int doc) throws IOException {
|
||||||
|
// we dont have enough information (the docid is needed)
|
||||||
|
throw new UnsupportedOperationException("this comparator cannot be used with deep paging");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copy(int slot, int doc) throws IOException {
|
||||||
|
childSlots[slot] = doc;
|
||||||
|
parentSlots[slot] = parent(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBottom(int slot) {
|
||||||
|
bottomParent = parentSlots[slot];
|
||||||
|
bottomChild = childSlots[slot];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setScorer(Scorer scorer) {
|
||||||
|
for (LeafFieldComparator comp : parentLeafComparators) {
|
||||||
|
comp.setScorer(scorer);
|
||||||
|
}
|
||||||
|
for (LeafFieldComparator comp : childLeafComparators) {
|
||||||
|
comp.setScorer(scorer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -168,32 +178,21 @@ public class BlockJoinComparatorSource extends FieldComparatorSource {
|
||||||
// really our sort "value" is more complex...
|
// really our sort "value" is more complex...
|
||||||
throw new UnsupportedOperationException("filling sort field values is not yet supported");
|
throw new UnsupportedOperationException("filling sort field values is not yet supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setScorer(Scorer scorer) {
|
|
||||||
super.setScorer(scorer);
|
|
||||||
for (FieldComparator<?> comp : parentComparators) {
|
|
||||||
comp.setScorer(scorer);
|
|
||||||
}
|
|
||||||
for (FieldComparator<?> comp : childComparators) {
|
|
||||||
comp.setScorer(scorer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int parent(int doc) {
|
int parent(int doc) {
|
||||||
return parentBits.nextSetBit(doc);
|
return parentBits.nextSetBit(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
int compare(int docID1, int parent1, int docID2, int parent2) throws IOException {
|
int compare(int docID1, int parent1, int docID2, int parent2) throws IOException {
|
||||||
if (parent1 == parent2) { // both are in the same block
|
if (parent1 == parent2) { // both are in the same block
|
||||||
if (docID1 == parent1 || docID2 == parent2) {
|
if (docID1 == parent1 || docID2 == parent2) {
|
||||||
// keep parents at the end of blocks
|
// keep parents at the end of blocks
|
||||||
return docID1 - docID2;
|
return docID1 - docID2;
|
||||||
} else {
|
} else {
|
||||||
return compare(docID1, docID2, childComparators, childReverseMul);
|
return compare(docID1, docID2, childLeafComparators, childReverseMul);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int cmp = compare(parent1, parent2, parentComparators, parentReverseMul);
|
int cmp = compare(parent1, parent2, parentLeafComparators, parentReverseMul);
|
||||||
if (cmp == 0) {
|
if (cmp == 0) {
|
||||||
return parent1 - parent2;
|
return parent1 - parent2;
|
||||||
} else {
|
} else {
|
||||||
|
@ -201,8 +200,8 @@ public class BlockJoinComparatorSource extends FieldComparatorSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int compare(int docID1, int docID2, FieldComparator<?> comparators[], int reverseMul[]) throws IOException {
|
int compare(int docID1, int docID2, LeafFieldComparator comparators[], int reverseMul[]) throws IOException {
|
||||||
for (int i = 0; i < comparators.length; i++) {
|
for (int i = 0; i < comparators.length; i++) {
|
||||||
// TODO: would be better if copy() didnt cause a term lookup in TermOrdVal & co,
|
// TODO: would be better if copy() didnt cause a term lookup in TermOrdVal & co,
|
||||||
// the segments are always the same here...
|
// the segments are always the same here...
|
||||||
|
@ -217,7 +216,7 @@ public class BlockJoinComparatorSource extends FieldComparatorSource {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "blockJoin(parentSort=" + parentSort + ",childSort=" + childSort + ")";
|
return "blockJoin(parentSort=" + parentSort + ",childSort=" + childSort + ")";
|
||||||
|
|
|
@ -17,16 +17,17 @@ package org.apache.lucene.queries.function;
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.lucene.index.LeafReaderContext;
|
import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.search.FieldComparator;
|
import org.apache.lucene.search.FieldComparator;
|
||||||
import org.apache.lucene.search.FieldComparatorSource;
|
import org.apache.lucene.search.FieldComparatorSource;
|
||||||
import org.apache.lucene.search.IndexSearcher;
|
import org.apache.lucene.search.IndexSearcher;
|
||||||
|
import org.apache.lucene.search.SimpleFieldComparator;
|
||||||
import org.apache.lucene.search.SortField;
|
import org.apache.lucene.search.SortField;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.IdentityHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates {@link FunctionValues} for a particular reader.
|
* Instantiates {@link FunctionValues} for a particular reader.
|
||||||
* <br>
|
* <br>
|
||||||
|
@ -126,7 +127,7 @@ public abstract class ValueSource {
|
||||||
* off of the {@link FunctionValues} for a ValueSource
|
* off of the {@link FunctionValues} for a ValueSource
|
||||||
* instead of the normal Lucene FieldComparator that works off of a FieldCache.
|
* instead of the normal Lucene FieldComparator that works off of a FieldCache.
|
||||||
*/
|
*/
|
||||||
class ValueSourceComparator extends FieldComparator<Double> {
|
class ValueSourceComparator extends SimpleFieldComparator<Double> {
|
||||||
private final double[] values;
|
private final double[] values;
|
||||||
private FunctionValues docVals;
|
private FunctionValues docVals;
|
||||||
private double bottom;
|
private double bottom;
|
||||||
|
@ -154,9 +155,8 @@ public abstract class ValueSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldComparator setNextReader(LeafReaderContext context) throws IOException {
|
public void doSetNextReader(LeafReaderContext context) throws IOException {
|
||||||
docVals = getValues(fcontext, context);
|
docVals = getValues(fcontext, context);
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -23,7 +23,7 @@ import java.text.Collator;
|
||||||
import org.apache.lucene.index.LeafReaderContext;
|
import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.index.BinaryDocValues;
|
import org.apache.lucene.index.BinaryDocValues;
|
||||||
import org.apache.lucene.index.DocValues;
|
import org.apache.lucene.index.DocValues;
|
||||||
import org.apache.lucene.search.FieldComparator;
|
import org.apache.lucene.search.SimpleFieldComparator;
|
||||||
import org.apache.lucene.util.Bits;
|
import org.apache.lucene.util.Bits;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ import org.apache.lucene.util.BytesRef;
|
||||||
* This class will be removed in Lucene 5.0
|
* This class will be removed in Lucene 5.0
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public final class SlowCollatedStringComparator extends FieldComparator<String> {
|
public final class SlowCollatedStringComparator extends SimpleFieldComparator<String> {
|
||||||
|
|
||||||
private final String[] values;
|
private final String[] values;
|
||||||
private BinaryDocValues currentDocTerms;
|
private BinaryDocValues currentDocTerms;
|
||||||
|
@ -93,10 +93,9 @@ public final class SlowCollatedStringComparator extends FieldComparator<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldComparator<String> setNextReader(LeafReaderContext context) throws IOException {
|
protected void doSetNextReader(LeafReaderContext context) throws IOException {
|
||||||
currentDocTerms = DocValues.getBinary(context.reader(), field);
|
currentDocTerms = DocValues.getBinary(context.reader(), field);
|
||||||
docsWithField = DocValues.getDocsWithField(context.reader(), field);
|
docsWithField = DocValues.getDocsWithField(context.reader(), field);
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.lucene.index.ReaderUtil;
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
import org.apache.lucene.search.BooleanQuery;
|
import org.apache.lucene.search.BooleanQuery;
|
||||||
import org.apache.lucene.search.FieldComparator;
|
import org.apache.lucene.search.FieldComparator;
|
||||||
|
import org.apache.lucene.search.LeafFieldComparator;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
import org.apache.lucene.search.ScoreDoc;
|
import org.apache.lucene.search.ScoreDoc;
|
||||||
import org.apache.lucene.search.Scorer;
|
import org.apache.lucene.search.Scorer;
|
||||||
|
@ -598,7 +599,8 @@ public class QueryComponent extends SearchComponent
|
||||||
// :TODO: would be simpler to always serialize every position of SortField[]
|
// :TODO: would be simpler to always serialize every position of SortField[]
|
||||||
if (type==SortField.Type.SCORE || type==SortField.Type.DOC) continue;
|
if (type==SortField.Type.SCORE || type==SortField.Type.DOC) continue;
|
||||||
|
|
||||||
FieldComparator comparator = null;
|
FieldComparator<?> comparator = null;
|
||||||
|
LeafFieldComparator leafComparator = null;
|
||||||
Object[] vals = new Object[nDocs];
|
Object[] vals = new Object[nDocs];
|
||||||
|
|
||||||
int lastIdx = -1;
|
int lastIdx = -1;
|
||||||
|
@ -621,12 +623,12 @@ public class QueryComponent extends SearchComponent
|
||||||
|
|
||||||
if (comparator == null) {
|
if (comparator == null) {
|
||||||
comparator = sortField.getComparator(1,0);
|
comparator = sortField.getComparator(1,0);
|
||||||
comparator = comparator.setNextReader(currentLeaf);
|
leafComparator = comparator.getLeafComparator(currentLeaf);
|
||||||
}
|
}
|
||||||
|
|
||||||
doc -= currentLeaf.docBase; // adjust for what segment this is in
|
doc -= currentLeaf.docBase; // adjust for what segment this is in
|
||||||
comparator.setScorer(new FakeScorer(doc, score));
|
leafComparator.setScorer(new FakeScorer(doc, score));
|
||||||
comparator.copy(0, doc);
|
leafComparator.copy(0, doc);
|
||||||
Object val = comparator.value(0);
|
Object val = comparator.value(0);
|
||||||
if (null != ft) val = ft.marshalSortValue(val);
|
if (null != ft) val = ft.marshalSortValue(val);
|
||||||
vals[position] = val;
|
vals[position] = val;
|
||||||
|
|
|
@ -36,6 +36,7 @@ import org.apache.lucene.search.DocIdSetIterator;
|
||||||
import org.apache.lucene.search.FieldComparator;
|
import org.apache.lucene.search.FieldComparator;
|
||||||
import org.apache.lucene.search.FieldComparatorSource;
|
import org.apache.lucene.search.FieldComparatorSource;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
|
import org.apache.lucene.search.SimpleFieldComparator;
|
||||||
import org.apache.lucene.search.Sort;
|
import org.apache.lucene.search.Sort;
|
||||||
import org.apache.lucene.search.SortField;
|
import org.apache.lucene.search.SortField;
|
||||||
import org.apache.lucene.search.TermQuery;
|
import org.apache.lucene.search.TermQuery;
|
||||||
|
@ -631,7 +632,7 @@ public class QueryElevationComponent extends SearchComponent implements SolrCore
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldComparator<Integer> newComparator(String fieldname, final int numHits, int sortPos, boolean reversed) throws IOException {
|
public FieldComparator<Integer> newComparator(String fieldname, final int numHits, int sortPos, boolean reversed) throws IOException {
|
||||||
return new FieldComparator<Integer>() {
|
return new SimpleFieldComparator<Integer>() {
|
||||||
private final int[] values = new int[numHits];
|
private final int[] values = new int[numHits];
|
||||||
private int bottomVal;
|
private int bottomVal;
|
||||||
private int topVal;
|
private int topVal;
|
||||||
|
@ -677,13 +678,13 @@ public class QueryElevationComponent extends SearchComponent implements SolrCore
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldComparator setNextReader(LeafReaderContext context) throws IOException {
|
protected void doSetNextReader(LeafReaderContext context) throws IOException {
|
||||||
//convert the ids to Lucene doc ids, the ordSet and termValues needs to be the same size as the number of elevation docs we have
|
//convert the ids to Lucene doc ids, the ordSet and termValues needs to be the same size as the number of elevation docs we have
|
||||||
ordSet.clear();
|
ordSet.clear();
|
||||||
Fields fields = context.reader().fields();
|
Fields fields = context.reader().fields();
|
||||||
if (fields == null) return this;
|
if (fields == null) return;
|
||||||
Terms terms = fields.terms(idField);
|
Terms terms = fields.terms(idField);
|
||||||
if (terms == null) return this;
|
if (terms == null) return;
|
||||||
termsEnum = terms.iterator(termsEnum);
|
termsEnum = terms.iterator(termsEnum);
|
||||||
BytesRefBuilder term = new BytesRefBuilder();
|
BytesRefBuilder term = new BytesRefBuilder();
|
||||||
Bits liveDocs = context.reader().getLiveDocs();
|
Bits liveDocs = context.reader().getLiveDocs();
|
||||||
|
@ -701,7 +702,6 @@ public class QueryElevationComponent extends SearchComponent implements SolrCore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -109,7 +109,7 @@ public class RandomSortField extends FieldType {
|
||||||
private static FieldComparatorSource randomComparatorSource = new FieldComparatorSource() {
|
private static FieldComparatorSource randomComparatorSource = new FieldComparatorSource() {
|
||||||
@Override
|
@Override
|
||||||
public FieldComparator<Integer> newComparator(final String fieldname, final int numHits, int sortPos, boolean reversed) {
|
public FieldComparator<Integer> newComparator(final String fieldname, final int numHits, int sortPos, boolean reversed) {
|
||||||
return new FieldComparator<Integer>() {
|
return new SimpleFieldComparator<Integer>() {
|
||||||
int seed;
|
int seed;
|
||||||
private final int[] values = new int[numHits];
|
private final int[] values = new int[numHits];
|
||||||
int bottomVal;
|
int bottomVal;
|
||||||
|
@ -141,9 +141,8 @@ public class RandomSortField extends FieldType {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldComparator setNextReader(LeafReaderContext context) {
|
protected void doSetNextReader(LeafReaderContext context) {
|
||||||
seed = getSeed(fieldname, context);
|
seed = getSeed(fieldname, context);
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -26,7 +26,6 @@ import org.apache.solr.common.util.NamedList;
|
||||||
import org.apache.solr.request.SolrQueryRequest;
|
import org.apache.solr.request.SolrQueryRequest;
|
||||||
import org.apache.solr.common.params.SolrParams;
|
import org.apache.solr.common.params.SolrParams;
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -129,22 +128,32 @@ public class ExportQParserPlugin extends QParserPlugin {
|
||||||
private class ExportCollector extends TopDocsCollector {
|
private class ExportCollector extends TopDocsCollector {
|
||||||
|
|
||||||
private FixedBitSet[] sets;
|
private FixedBitSet[] sets;
|
||||||
private FixedBitSet set;
|
|
||||||
|
|
||||||
public ExportCollector(FixedBitSet[] sets) {
|
public ExportCollector(FixedBitSet[] sets) {
|
||||||
super(null);
|
super(null);
|
||||||
this.sets = sets;
|
this.sets = sets;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doSetNextReader(LeafReaderContext context) throws IOException {
|
|
||||||
this.set = new FixedBitSet(context.reader().maxDoc());
|
|
||||||
this.sets[context.ord] = set;
|
|
||||||
|
|
||||||
}
|
@Override
|
||||||
|
public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException {
|
||||||
public void collect(int docId) throws IOException{
|
final FixedBitSet set = new FixedBitSet(context.reader().maxDoc());
|
||||||
++totalHits;
|
this.sets[context.ord] = set;
|
||||||
set.set(docId);
|
return new LeafCollector() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setScorer(Scorer scorer) throws IOException {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void collect(int docId) throws IOException{
|
||||||
|
++totalHits;
|
||||||
|
set.set(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean acceptsDocsOutOfOrder() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScoreDoc[] getScoreDocs(int howMany) {
|
private ScoreDoc[] getScoreDocs(int howMany) {
|
||||||
|
@ -170,12 +179,5 @@ public class ExportQParserPlugin extends QParserPlugin {
|
||||||
return new TopDocs(totalHits, scoreDocs, 0.0f);
|
return new TopDocs(totalHits, scoreDocs, 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setScorer(Scorer scorer) throws IOException {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean acceptsDocsOutOfOrder() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,6 +18,7 @@
|
||||||
package org.apache.solr.search;
|
package org.apache.solr.search;
|
||||||
|
|
||||||
import com.carrotsearch.hppc.IntIntOpenHashMap;
|
import com.carrotsearch.hppc.IntIntOpenHashMap;
|
||||||
|
|
||||||
import org.apache.lucene.index.LeafReaderContext;
|
import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.search.Explanation;
|
import org.apache.lucene.search.Explanation;
|
||||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||||
|
@ -33,7 +34,7 @@ import org.apache.solr.common.util.NamedList;
|
||||||
import org.apache.solr.handler.component.MergeStrategy;
|
import org.apache.solr.handler.component.MergeStrategy;
|
||||||
import org.apache.solr.handler.component.QueryElevationComponent;
|
import org.apache.solr.handler.component.QueryElevationComponent;
|
||||||
import org.apache.solr.request.SolrQueryRequest;
|
import org.apache.solr.request.SolrQueryRequest;
|
||||||
|
import org.apache.lucene.search.LeafCollector;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
import org.apache.lucene.search.Weight;
|
import org.apache.lucene.search.Weight;
|
||||||
import org.apache.lucene.search.IndexSearcher;
|
import org.apache.lucene.search.IndexSearcher;
|
||||||
|
@ -43,6 +44,7 @@ import org.apache.lucene.search.Sort;
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
import org.apache.lucene.index.IndexReader;
|
import org.apache.lucene.index.IndexReader;
|
||||||
import org.apache.lucene.search.ScoreDoc;
|
import org.apache.lucene.search.ScoreDoc;
|
||||||
|
|
||||||
import com.carrotsearch.hppc.IntFloatOpenHashMap;
|
import com.carrotsearch.hppc.IntFloatOpenHashMap;
|
||||||
|
|
||||||
import org.apache.lucene.util.Bits;
|
import org.apache.lucene.util.Bits;
|
||||||
|
@ -255,26 +257,15 @@ public class ReRankQParserPlugin extends QParserPlugin {
|
||||||
this.reRankWeight = reRankWeight;
|
this.reRankWeight = reRankWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean acceptsDocsOutOfOrder() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void collect(int doc) throws IOException {
|
|
||||||
mainCollector.collect(doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setScorer(Scorer scorer) throws IOException{
|
|
||||||
mainCollector.setScorer(scorer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void doSetNextReader(LeafReaderContext context) throws IOException{
|
|
||||||
mainCollector.getLeafCollector(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTotalHits() {
|
public int getTotalHits() {
|
||||||
return mainCollector.getTotalHits();
|
return mainCollector.getTotalHits();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException {
|
||||||
|
return mainCollector.getLeafCollector(context);
|
||||||
|
}
|
||||||
|
|
||||||
public TopDocs topDocs(int start, int howMany) {
|
public TopDocs topDocs(int start, int howMany) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -387,6 +378,7 @@ public class ReRankQParserPlugin extends QParserPlugin {
|
||||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
|
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoostedComp implements Comparator {
|
public class BoostedComp implements Comparator {
|
||||||
|
|
|
@ -2055,16 +2055,17 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable,SolrIn
|
||||||
int end=0;
|
int end=0;
|
||||||
int readerIndex = 0;
|
int readerIndex = 0;
|
||||||
|
|
||||||
|
LeafCollector leafCollector = null;
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
int doc = iter.nextDoc();
|
int doc = iter.nextDoc();
|
||||||
while (doc>=end) {
|
while (doc>=end) {
|
||||||
LeafReaderContext leaf = leafContexts.get(readerIndex++);
|
LeafReaderContext leaf = leafContexts.get(readerIndex++);
|
||||||
base = leaf.docBase;
|
base = leaf.docBase;
|
||||||
end = base + leaf.reader().maxDoc();
|
end = base + leaf.reader().maxDoc();
|
||||||
topCollector.getLeafCollector(leaf);
|
leafCollector = topCollector.getLeafCollector(leaf);
|
||||||
// we should never need to set the scorer given the settings for the collector
|
// we should never need to set the scorer given the settings for the collector
|
||||||
}
|
}
|
||||||
topCollector.collect(doc-base);
|
leafCollector.collect(doc-base);
|
||||||
}
|
}
|
||||||
|
|
||||||
TopDocs topDocs = topCollector.topDocs(0, nDocs);
|
TopDocs topDocs = topCollector.topDocs(0, nDocs);
|
||||||
|
|
|
@ -23,6 +23,8 @@ import org.apache.lucene.index.IndexReaderContext;
|
||||||
import org.apache.lucene.index.NumericDocValues;
|
import org.apache.lucene.index.NumericDocValues;
|
||||||
import org.apache.lucene.index.ReaderUtil;
|
import org.apache.lucene.index.ReaderUtil;
|
||||||
import org.apache.lucene.search.FieldComparator;
|
import org.apache.lucene.search.FieldComparator;
|
||||||
|
import org.apache.lucene.search.LeafCollector;
|
||||||
|
import org.apache.lucene.search.LeafFieldComparator;
|
||||||
import org.apache.lucene.search.ScoreDoc;
|
import org.apache.lucene.search.ScoreDoc;
|
||||||
import org.apache.lucene.search.Sort;
|
import org.apache.lucene.search.Sort;
|
||||||
import org.apache.lucene.search.SortField;
|
import org.apache.lucene.search.SortField;
|
||||||
|
@ -51,7 +53,6 @@ import org.apache.solr.schema.FieldType;
|
||||||
import org.apache.solr.schema.IndexSchema;
|
import org.apache.solr.schema.IndexSchema;
|
||||||
import org.apache.solr.schema.SchemaField;
|
import org.apache.solr.schema.SchemaField;
|
||||||
import org.apache.solr.request.SolrQueryRequest;
|
import org.apache.solr.request.SolrQueryRequest;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -410,7 +411,8 @@ public class TestRankQueryPlugin extends QParserPlugin {
|
||||||
// :TODO: would be simpler to always serialize every position of SortField[]
|
// :TODO: would be simpler to always serialize every position of SortField[]
|
||||||
if (type==SortField.Type.SCORE || type==SortField.Type.DOC) continue;
|
if (type==SortField.Type.SCORE || type==SortField.Type.DOC) continue;
|
||||||
|
|
||||||
FieldComparator comparator = null;
|
FieldComparator<?> comparator = null;
|
||||||
|
LeafFieldComparator leafComparator = null;
|
||||||
Object[] vals = new Object[nDocs];
|
Object[] vals = new Object[nDocs];
|
||||||
|
|
||||||
int lastIdx = -1;
|
int lastIdx = -1;
|
||||||
|
@ -433,12 +435,12 @@ public class TestRankQueryPlugin extends QParserPlugin {
|
||||||
|
|
||||||
if (comparator == null) {
|
if (comparator == null) {
|
||||||
comparator = sortField.getComparator(1,0);
|
comparator = sortField.getComparator(1,0);
|
||||||
comparator = comparator.setNextReader(currentLeaf);
|
leafComparator = comparator.getLeafComparator(currentLeaf);
|
||||||
}
|
}
|
||||||
|
|
||||||
doc -= currentLeaf.docBase; // adjust for what segment this is in
|
doc -= currentLeaf.docBase; // adjust for what segment this is in
|
||||||
comparator.setScorer(new FakeScorer(doc, score));
|
leafComparator.setScorer(new FakeScorer(doc, score));
|
||||||
comparator.copy(0, doc);
|
leafComparator.copy(0, doc);
|
||||||
Object val = comparator.value(0);
|
Object val = comparator.value(0);
|
||||||
if (null != ft) val = ft.marshalSortValue(val);
|
if (null != ft) val = ft.marshalSortValue(val);
|
||||||
vals[position] = val;
|
vals[position] = val;
|
||||||
|
@ -705,24 +707,28 @@ public class TestRankQueryPlugin extends QParserPlugin {
|
||||||
class TestCollector extends TopDocsCollector {
|
class TestCollector extends TopDocsCollector {
|
||||||
|
|
||||||
private List<ScoreDoc> list = new ArrayList();
|
private List<ScoreDoc> list = new ArrayList();
|
||||||
private NumericDocValues values;
|
|
||||||
private int base;
|
|
||||||
|
|
||||||
public TestCollector(PriorityQueue pq) {
|
public TestCollector(PriorityQueue pq) {
|
||||||
super(pq);
|
super(pq);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean acceptsDocsOutOfOrder() {
|
@Override
|
||||||
return false;
|
public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException {
|
||||||
}
|
final int base = context.docBase;
|
||||||
|
final NumericDocValues values = DocValues.getNumeric(context.reader(), "sort_i");
|
||||||
|
return new LeafCollector() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setScorer(Scorer scorer) throws IOException {}
|
||||||
|
|
||||||
|
public boolean acceptsDocsOutOfOrder() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public void doSetNextReader(LeafReaderContext context) throws IOException {
|
public void collect(int doc) {
|
||||||
values = DocValues.getNumeric(context.reader(), "sort_i");
|
list.add(new ScoreDoc(doc+base, (float)values.get(doc)));
|
||||||
base = context.docBase;
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
public void collect(int doc) {
|
|
||||||
list.add(new ScoreDoc(doc+base, (float)values.get(doc)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int topDocsSize() {
|
public int topDocsSize() {
|
||||||
|
@ -759,27 +765,32 @@ public class TestRankQueryPlugin extends QParserPlugin {
|
||||||
class TestCollector1 extends TopDocsCollector {
|
class TestCollector1 extends TopDocsCollector {
|
||||||
|
|
||||||
private List<ScoreDoc> list = new ArrayList();
|
private List<ScoreDoc> list = new ArrayList();
|
||||||
private int base;
|
|
||||||
private Scorer scorer;
|
|
||||||
|
|
||||||
public TestCollector1(PriorityQueue pq) {
|
public TestCollector1(PriorityQueue pq) {
|
||||||
super(pq);
|
super(pq);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean acceptsDocsOutOfOrder() {
|
@Override
|
||||||
return false;
|
public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException {
|
||||||
}
|
final int base = context.docBase;
|
||||||
|
return new LeafCollector() {
|
||||||
public void doSetNextReader(LeafReaderContext context) throws IOException {
|
|
||||||
base = context.docBase;
|
Scorer scorer;
|
||||||
}
|
|
||||||
|
@Override
|
||||||
public void setScorer(Scorer scorer) {
|
public void setScorer(Scorer scorer) throws IOException {
|
||||||
this.scorer = scorer;
|
this.scorer = scorer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void collect(int doc) throws IOException {
|
public void collect(int doc) throws IOException {
|
||||||
list.add(new ScoreDoc(doc+base, scorer.score()));
|
list.add(new ScoreDoc(doc+base, scorer.score()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean acceptsDocsOutOfOrder() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public int topDocsSize() {
|
public int topDocsSize() {
|
||||||
|
@ -813,7 +824,4 @@ public class TestRankQueryPlugin extends QParserPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue