Index: lucene/contrib/queries/src/java/org/apache/lucene/search/SlowCollatedStringComparator.java
--- lucene/contrib/queries/src/java/org/apache/lucene/search/SlowCollatedStringComparator.java Fri Jun 10 16:56:32 2011 -0400
+++ lucene/contrib/queries/src/java/org/apache/lucene/search/SlowCollatedStringComparator.java Fri Jun 10 19:12:55 2011 -0400
@@ -33,7 +33,7 @@
* This class will be removed in Lucene 5.0
*/
@Deprecated
-public final class SlowCollatedStringComparator extends FieldComparator {
+public final class SlowCollatedStringComparator extends FieldComparator {
private final String[] values;
private DocTerms currentDocTerms;
@@ -99,8 +99,22 @@
}
@Override
- public Comparable> value(int slot) {
+ public BytesRef value(int slot) {
final String s = values[slot];
return s == null ? null : new BytesRef(values[slot]);
}
+
+ @Override
+ public int compareValues(BytesRef first, BytesRef second) {
+ if (first == null) {
+ if (second == null) {
+ return 0;
+ }
+ return -1;
+ } else if (second == null) {
+ return 1;
+ } else {
+ return collator.compare(first, second);
+ }
+ }
}
Index: lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFieldComparatorSource.java
--- lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFieldComparatorSource.java Fri Jun 10 16:56:32 2011 -0400
+++ lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFieldComparatorSource.java Fri Jun 10 19:12:55 2011 -0400
@@ -31,94 +31,104 @@
*/
public class DistanceFieldComparatorSource extends FieldComparatorSource {
- private DistanceFilter distanceFilter;
- private DistanceScoreDocLookupComparator dsdlc;
+ private DistanceFilter distanceFilter;
+ private DistanceScoreDocLookupComparator dsdlc;
- public DistanceFieldComparatorSource(Filter distanceFilter) {
+ public DistanceFieldComparatorSource(Filter distanceFilter) {
+ this.distanceFilter = (DistanceFilter) distanceFilter;
+ }
- this.distanceFilter = (DistanceFilter) distanceFilter;
+ public void cleanUp() {
+ distanceFilter = null;
- }
+ if (dsdlc != null) {
+ dsdlc.cleanUp();
+ }
- public void cleanUp() {
- distanceFilter = null;
+ dsdlc = null;
+ }
- if (dsdlc != null)
- dsdlc.cleanUp();
+ @Override
+ public FieldComparator newComparator(String fieldname, int numHits,
+ int sortPos, boolean reversed) throws IOException {
+ dsdlc = new DistanceScoreDocLookupComparator(numHits);
+ return dsdlc;
+ }
- dsdlc = null;
- }
+ private class DistanceScoreDocLookupComparator extends FieldComparator {
- @Override
- public FieldComparator newComparator(String fieldname, int numHits,
- int sortPos, boolean reversed) throws IOException {
- dsdlc = new DistanceScoreDocLookupComparator(numHits);
- return dsdlc;
- }
+ private double[] values;
+ private double bottom;
+ private int offset =0;
+
+ public DistanceScoreDocLookupComparator(int numHits) {
+ values = new double[numHits];
+ return;
+ }
- private class DistanceScoreDocLookupComparator extends FieldComparator {
+ @Override
+ public int compare(int slot1, int slot2) {
+ double a = values[slot1];
+ double b = values[slot2];
+ if (a > b)
+ return 1;
+ if (a < b)
+ return -1;
- private double[] values;
- private double bottom;
- private int offset =0;
-
- public DistanceScoreDocLookupComparator(int numHits) {
- values = new double[numHits];
- return;
- }
+ return 0;
+ }
- @Override
- public int compare(int slot1, int slot2) {
- double a = values[slot1];
- double b = values[slot2];
- if (a > b)
- return 1;
- if (a < b)
- return -1;
+ public void cleanUp() {
+ distanceFilter = null;
+ }
- return 0;
- }
+ @Override
+ public int compareBottom(int doc) {
+ double v2 = distanceFilter.getDistance(doc+ offset);
+
+ if (bottom > v2) {
+ return 1;
+ } else if (bottom < v2) {
+ return -1;
+ }
+ return 0;
+ }
- public void cleanUp() {
- distanceFilter = null;
- }
+ @Override
+ public void copy(int slot, int doc) {
+ values[slot] = distanceFilter.getDistance(doc + offset);
+ }
- @Override
- public int compareBottom(int doc) {
- double v2 = distanceFilter.getDistance(doc+ offset);
-
- if (bottom > v2) {
- return 1;
- } else if (bottom < v2) {
- return -1;
- }
- return 0;
- }
-
- @Override
- public void copy(int slot, int doc) {
- values[slot] = distanceFilter.getDistance(doc + offset);
- }
-
- @Override
- public void setBottom(int slot) {
- this.bottom = values[slot];
-
- }
+ @Override
+ public void setBottom(int slot) {
+ this.bottom = values[slot];
+ }
@Override
public FieldComparator setNextReader(AtomicReaderContext context)
- throws IOException {
+ throws IOException {
// each reader in a segmented base
// has an offset based on the maxDocs of previous readers
offset = context.docBase;
return this;
}
- @Override
- public Comparable value(int slot) {
- return values[slot];
- }
- }
+ @Override
+ public Double value(int slot) {
+ return values[slot];
+ }
+ @Override
+ public int compareValues(Double first, Double second) {
+ double v1 = first.doubleValue();
+ double v2 = second.doubleValue();
+ if (v1 > v2) {
+ return 1;
+ } else if (v1 < v2) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+ }
}
Index: lucene/src/java/org/apache/lucene/search/FieldComparator.java
--- lucene/src/java/org/apache/lucene/search/FieldComparator.java Fri Jun 10 16:56:32 2011 -0400
+++ lucene/src/java/org/apache/lucene/search/FieldComparator.java Fri Jun 10 19:12:55 2011 -0400
@@ -96,7 +96,7 @@
*
* @lucene.experimental
*/
-public abstract class FieldComparator {
+public abstract class FieldComparator {
/**
* Compare hit at slot1 with hit at slot2.
@@ -176,13 +176,14 @@
* Return the actual value in the slot.
*
* @param slot the value
- * @return value in this slot upgraded to Comparable
+ * @return value in this slot
*/
- public abstract Comparable> value(int slot);
+ public abstract T value(int slot);
-
+ /** Returns -1 if first is less than second. */
+ public abstract int compareValues(T first, T second);
- public static abstract class NumericComparator extends FieldComparator {
+ public static abstract class NumericComparator extends FieldComparator {
protected final CachedArrayCreator creator;
protected T cached;
protected final boolean checkMissing;
@@ -199,11 +200,19 @@
valid = cached.valid;
return this;
}
+
+ @Override @SuppressWarnings("unchecked")
+ public int compareValues(U first, U second) {
+ // Just natural order for all numerics
+ // very strange: java.lang.Number itsself is not
+ // Comparable, but all subclasses used here are
+ return ((Comparable) first).compareTo(second);
+ }
}
/** Parses field's values as byte (using {@link
* FieldCache#getBytes} and sorts by ascending value */
- public static final class ByteComparator extends NumericComparator {
+ public static final class ByteComparator extends NumericComparator {
private byte[] docValues;
private final byte[] values;
private final byte missingValue;
@@ -252,7 +261,7 @@
}
@Override
- public Comparable> value(int slot) {
+ public Byte value(int slot) {
return Byte.valueOf(values[slot]);
}
}
@@ -260,13 +269,12 @@
/** Parses field's values as double (using {@link
* FieldCache#getDoubles} and sorts by ascending value */
- public static final class DoubleComparator extends NumericComparator {
+ public static final class DoubleComparator extends NumericComparator {
private double[] docValues;
private final double[] values;
private final double missingValue;
private double bottom;
-
DoubleComparator(int numHits, DoubleValuesCreator creator, Double missingValue ) {
super( creator, missingValue != null );
values = new double[numHits];
@@ -324,13 +332,13 @@
}
@Override
- public Comparable> value(int slot) {
+ public Double value(int slot) {
return Double.valueOf(values[slot]);
}
}
/** Uses float index values to sort by ascending value */
- public static final class FloatDocValuesComparator extends FieldComparator {
+ public static final class FloatDocValuesComparator extends FieldComparator {
private final double[] values;
private Source currentReaderValues;
private final String field;
@@ -386,14 +394,25 @@
}
@Override
- public Comparable value(int slot) {
+ public Double value(int slot) {
return Double.valueOf(values[slot]);
}
+
+ @Override
+ public int compareValues(Double first, Double second) {
+ if (first < second) {
+ return -1;
+ } else if (first > second) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
}
/** Parses field's values as float (using {@link
* FieldCache#getFloats} and sorts by ascending value */
- public static final class FloatComparator extends NumericComparator {
+ public static final class FloatComparator extends NumericComparator {
private float[] docValues;
private final float[] values;
private final float missingValue;
@@ -460,14 +479,14 @@
}
@Override
- public Comparable> value(int slot) {
+ public Float value(int slot) {
return Float.valueOf(values[slot]);
}
}
/** Parses field's values as short (using {@link
* FieldCache#getShorts} and sorts by ascending value */
- public static final class ShortComparator extends NumericComparator {
+ public static final class ShortComparator extends NumericComparator {
private short[] docValues;
private final short[] values;
private short bottom;
@@ -516,14 +535,14 @@
}
@Override
- public Comparable> value(int slot) {
+ public Short value(int slot) {
return Short.valueOf(values[slot]);
}
}
/** Parses field's values as int (using {@link
* FieldCache#getInts} and sorts by ascending value */
- public static final class IntComparator extends NumericComparator {
+ public static final class IntComparator extends NumericComparator {
private int[] docValues;
private final int[] values;
private int bottom; // Value of bottom of queue
@@ -594,13 +613,13 @@
}
@Override
- public Comparable> value(int slot) {
+ public Integer value(int slot) {
return Integer.valueOf(values[slot]);
}
}
/** Loads int index values and sorts by ascending value. */
- public static final class IntDocValuesComparator extends FieldComparator {
+ public static final class IntDocValuesComparator extends FieldComparator {
private final long[] values;
private Source currentReaderValues;
private final String field;
@@ -660,14 +679,25 @@
}
@Override
- public Comparable value(int slot) {
+ public Long value(int slot) {
return Long.valueOf(values[slot]);
}
+
+ @Override
+ public int compareValues(Long first, Long second) {
+ if (first > second) {
+ return 1;
+ } else if (first < second) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
}
/** Parses field's values as long (using {@link
* FieldCache#getLongs} and sorts by ascending value */
- public static final class LongComparator extends NumericComparator {
+ public static final class LongComparator extends NumericComparator {
private long[] docValues;
private final long[] values;
private long bottom;
@@ -735,7 +765,7 @@
}
@Override
- public Comparable> value(int slot) {
+ public Long value(int slot) {
return Long.valueOf(values[slot]);
}
}
@@ -746,7 +776,7 @@
* using {@link TopScoreDocCollector} directly (which {@link
* IndexSearcher#search} uses when no {@link Sort} is
* specified). */
- public static final class RelevanceComparator extends FieldComparator {
+ public static final class RelevanceComparator extends FieldComparator {
private final float[] scores;
private float bottom;
private Scorer scorer;
@@ -791,15 +821,24 @@
}
@Override
- public Comparable> value(int slot) {
+ public Float value(int slot) {
return Float.valueOf(scores[slot]);
}
+
+ @Override
+ public int compareValues(Float first, Float second) {
+ if (first > second) {
+ return -1;
+ } else if (first < second) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
}
-
-
/** Sorts by ascending docID */
- public static final class DocComparator extends FieldComparator {
+ public static final class DocComparator extends FieldComparator {
private final int[] docIDs;
private int docBase;
private int bottom;
@@ -840,9 +879,15 @@
}
@Override
- public Comparable> value(int slot) {
+ public Integer value(int slot) {
return Integer.valueOf(docIDs[slot]);
}
+
+ @Override
+ public int compareValues(Integer first, Integer second) {
+ // No overflow risk because docIDs are non-negative
+ return first.intValue() - second.intValue();
+ }
}
/** Sorts by field's natural Term sort order, using
@@ -854,7 +899,7 @@
* to large results, this comparator will be much faster
* than {@link TermValComparator}. For very small
* result sets it may be slower. */
- public static final class TermOrdValComparator extends FieldComparator {
+ public static final class TermOrdValComparator extends FieldComparator {
/** @lucene.internal */
final int[] ords;
/** @lucene.internal */
@@ -920,7 +965,7 @@
* the underlying array access when looking up doc->ord
* @lucene.internal
*/
- abstract class PerSegmentComparator extends FieldComparator {
+ abstract class PerSegmentComparator extends FieldComparator {
@Override
public FieldComparator setNextReader(AtomicReaderContext context) throws IOException {
@@ -938,9 +983,14 @@
}
@Override
- public Comparable> value(int slot) {
+ public BytesRef value(int slot) {
return TermOrdValComparator.this.value(slot);
}
+
+ @Override
+ public int compareValues(BytesRef first, BytesRef second) {
+ return first.compareTo(second);
+ }
}
// Used per-segment when bit width of doc->ord is 8:
@@ -1244,16 +1294,21 @@
}
@Override
- public Comparable> value(int slot) {
+ public BytesRef value(int slot) {
return values[slot];
}
+
+ @Override
+ public int compareValues(BytesRef first, BytesRef second) {
+ return first.compareTo(second);
+ }
}
/** Sorts by field's natural Term sort order. All
* comparisons are done using BytesRef.compareTo, which is
* slow for medium to large result sets but possibly
* very fast for very small results sets. */
- public static final class TermValComparator extends FieldComparator {
+ public static final class TermValComparator extends FieldComparator {
private BytesRef[] values;
private DocTerms docTerms;
@@ -1316,9 +1371,14 @@
}
@Override
- public Comparable> value(int slot) {
+ public BytesRef value(int slot) {
return values[slot];
}
+
+ @Override
+ public int compareValues(BytesRef first, BytesRef second) {
+ return first.compareTo(second);
+ }
}
final protected static int binarySearch(BytesRef br, DocTermsIndex a, BytesRef key) {
Index: lucene/src/java/org/apache/lucene/search/FieldDoc.java
--- lucene/src/java/org/apache/lucene/search/FieldDoc.java Fri Jun 10 16:56:32 2011 -0400
+++ lucene/src/java/org/apache/lucene/search/FieldDoc.java Fri Jun 10 19:12:55 2011 -0400
@@ -40,12 +40,13 @@
/** Expert: The values which are used to sort the referenced document.
* The order of these will match the original sort criteria given by a
- * Sort object. Each Object will be either an Integer, Float or String,
- * depending on the type of values in the terms of the original field.
+ * Sort object. Each Object will have been returned from
+ * the value method corresponding
+ * FieldComparator used to sort this field.
* @see Sort
* @see IndexSearcher#search(Query,Filter,int,Sort)
*/
- public Comparable[] fields;
+ public Object[] fields;
/** Expert: Creates one of these objects with empty sort information. */
public FieldDoc (int doc, float score) {
@@ -53,7 +54,7 @@
}
/** Expert: Creates one of these objects with the given sort information. */
- public FieldDoc (int doc, float score, Comparable[] fields) {
+ public FieldDoc (int doc, float score, Object[] fields) {
super (doc, score);
this.fields = fields;
}
Index: lucene/src/java/org/apache/lucene/search/FieldValueHitQueue.java
--- lucene/src/java/org/apache/lucene/search/FieldValueHitQueue.java Fri Jun 10 16:56:32 2011 -0400
+++ lucene/src/java/org/apache/lucene/search/FieldValueHitQueue.java Fri Jun 10 19:12:55 2011 -0400
@@ -200,7 +200,7 @@
*/
FieldDoc fillFields(final Entry entry) {
final int n = comparators.length;
- final Comparable>[] fields = new Comparable[n];
+ final Object[] fields = new Object[n];
for (int i = 0; i < n; ++i) {
fields[i] = comparators[i].value(entry.slot);
}
Index: lucene/src/java/org/apache/lucene/search/IndexSearcher.java
--- lucene/src/java/org/apache/lucene/search/IndexSearcher.java Fri Jun 10 16:56:32 2011 -0400
+++ lucene/src/java/org/apache/lucene/search/IndexSearcher.java Fri Jun 10 19:12:55 2011 -0400
@@ -443,7 +443,7 @@
* Collector)}.
*/
protected TopFieldDocs search(Weight weight, Filter filter, int nDocs,
- Sort sort, boolean fillFields)
+ Sort sort, boolean fillFields)
throws IOException {
if (sort == null) throw new NullPointerException();
Index: lucene/src/java/org/apache/lucene/search/SortField.java
--- lucene/src/java/org/apache/lucene/search/SortField.java Fri Jun 10 16:56:32 2011 -0400
+++ lucene/src/java/org/apache/lucene/search/SortField.java Fri Jun 10 19:12:55 2011 -0400
@@ -91,10 +91,10 @@
public static final int BYTES = 12;
/** Represents sorting by document score (relevance). */
- public static final SortField FIELD_SCORE = new SortField (null, SCORE);
+ public static final SortField FIELD_SCORE = new SortField(null, SCORE);
/** Represents sorting by document number (index order). */
- public static final SortField FIELD_DOC = new SortField (null, DOC);
+ public static final SortField FIELD_DOC = new SortField(null, DOC);
private String field;
private int type; // defaults to determining type dynamically
@@ -111,7 +111,7 @@
* type is SCORE or DOC.
* @param type Type of values in the terms.
*/
- public SortField (String field, int type) {
+ public SortField(String field, int type) {
initFieldType(field, type);
}
@@ -122,7 +122,7 @@
* @param type Type of values in the terms.
* @param reverse True if natural order should be reversed.
*/
- public SortField (String field, int type, boolean reverse) {
+ public SortField(String field, int type, boolean reverse) {
initFieldType(field, type);
this.reverse = reverse;
}
@@ -140,7 +140,7 @@
* @deprecated (4.0) use EntryCreator version
*/
@Deprecated
- public SortField (String field, FieldCache.Parser parser) {
+ public SortField(String field, FieldCache.Parser parser) {
this(field, parser, false);
}
@@ -158,7 +158,7 @@
* @deprecated (4.0) use EntryCreator version
*/
@Deprecated
- public SortField (String field, FieldCache.Parser parser, boolean reverse) {
+ public SortField(String field, FieldCache.Parser parser, boolean reverse) {
if (field == null) {
throw new IllegalArgumentException("field can only be null when type is SCORE or DOC");
}
@@ -225,7 +225,7 @@
* @param field Name of field to sort by; cannot be null.
* @param comparator Returns a comparator for sorting hits.
*/
- public SortField (String field, FieldComparatorSource comparator) {
+ public SortField(String field, FieldComparatorSource comparator) {
initFieldType(field, CUSTOM);
this.comparatorSource = comparator;
}
@@ -235,7 +235,7 @@
* @param comparator Returns a comparator for sorting hits.
* @param reverse True if natural order should be reversed.
*/
- public SortField (String field, FieldComparatorSource comparator, boolean reverse) {
+ public SortField(String field, FieldComparatorSource comparator, boolean reverse) {
initFieldType(field, CUSTOM);
this.reverse = reverse;
this.comparatorSource = comparator;
Index: lucene/src/java/org/apache/lucene/search/TopDocs.java
--- lucene/src/java/org/apache/lucene/search/TopDocs.java Fri Jun 10 16:56:32 2011 -0400
+++ lucene/src/java/org/apache/lucene/search/TopDocs.java Fri Jun 10 19:12:55 2011 -0400
@@ -17,6 +17,10 @@
* limitations under the License.
*/
+import java.io.IOException;
+
+import org.apache.lucene.util.PriorityQueue;
+
/** Represents hits returned by {@link
* IndexSearcher#search(Query,Filter,int)} and {@link
* IndexSearcher#search(Query,int)}. */
@@ -52,4 +56,212 @@
this.scoreDocs = scoreDocs;
this.maxScore = maxScore;
}
+
+ // Refers to one hit:
+ private static class ShardRef {
+ // Which shard (index into shardHits[]):
+ final int shardIndex;
+
+ // Which hit within the shard:
+ int hitIndex;
+
+ public ShardRef(int shardIndex) {
+ this.shardIndex = shardIndex;
+ }
+
+ @Override
+ public String toString() {
+ return "ShardRef(shardIndex=" + shardIndex + " hitIndex=" + hitIndex + ")";
+ }
+ };
+
+ // Specialized MergeSortQueue that just merges by
+ // relevance score, descending:
+ private static class ScoreMergeSortQueue extends PriorityQueue {
+ final ScoreDoc[][] shardHits;
+
+ public ScoreMergeSortQueue(TopDocs[] shardHits) {
+ super(shardHits.length);
+ this.shardHits = new ScoreDoc[shardHits.length][];
+ for(int shardIDX=0;shardIDX secondScore) {
+ return true;
+ } else {
+ // Tie break: earlier shard wins
+ if (first.shardIndex < second.shardIndex) {
+ return true;
+ } else if (first.shardIndex > second.shardIndex) {
+ return false;
+ } else {
+ // Tie break in same shard: resolve however the
+ // shard had resolved it:
+ assert first.hitIndex != second.hitIndex;
+ return first.hitIndex < second.hitIndex;
+ }
+ }
+ }
+ }
+
+ private static class MergeSortQueue extends PriorityQueue {
+ // These are really FieldDoc instances:
+ final ScoreDoc[][] shardHits;
+ final FieldComparator[] comparators;
+ final int[] reverseMul;
+
+ public MergeSortQueue(Sort sort, TopDocs[] shardHits) throws IOException {
+ super(shardHits.length);
+ this.shardHits = new ScoreDoc[shardHits.length][];
+ for(int shardIDX=0;shardIDX second.shardIndex) {
+ //System.out.println(" return tb false");
+ return false;
+ } else {
+ // Tie break in same shard: resolve however the
+ // shard had resolved it:
+ //System.out.println(" return tb " + (first.hitIndex < second.hitIndex));
+ assert first.hitIndex != second.hitIndex;
+ return first.hitIndex < second.hitIndex;
+ }
+ }
+ }
+
+ /** Returned from {@link #merge}, to include the merged
+ * TopDocs as well as the reference to which original
+ * TopDocs shard each hit came from.
+ *
+ * @lucene.experimental */
+ public static class TopDocsAndShards {
+
+ /** Merged hits from all shards */
+ public final TopDocs hits;
+
+ /** Parallel array matching hits.scoreDocs */
+ public final int[] shardIndex;
+
+ public TopDocsAndShards(TopDocs hits, int[] shardIndex) {
+ this.hits = hits;
+ this.shardIndex = shardIndex;
+ }
+ }
+
+ /** Returns a new TopDocs, containing topN results across
+ * the provided TopDocs, sorting by the specified {@link
+ * Sort}. Each of the TopDocs must have been sorted by
+ * the same Sort, and sort field values must have been
+ * filled (ie, fillFields=true must be
+ * passed to {@link
+ * TopFieldCollector#create}.
+ *
+ * Pass sort=null to merge sort by score descending.
+ *
+ * @lucene.experimental */
+ public static TopDocsAndShards merge(Sort sort, int topN, TopDocs[] shardHits) throws IOException {
+
+ final PriorityQueue queue;
+ if (sort == null) {
+ queue = new ScoreMergeSortQueue(shardHits);
+ } else {
+ queue = new MergeSortQueue(sort, shardHits);
+ }
+
+ int totalHitCount = 0;
+ float maxScore = Float.MIN_VALUE;
+ for(int shardIDX=0;shardIDX 0) {
+ totalHitCount += shard.totalHits;
+ queue.add(new ShardRef(shardIDX));
+ maxScore = Math.max(maxScore, shard.getMaxScore());
+ //System.out.println(" maxScore now " + maxScore + " vs " + shard.getMaxScore());
+ }
+ }
+
+ final ScoreDoc[] hits = new ScoreDoc[Math.min(topN, totalHitCount)];
+ final int[] shardIndex = new int[hits.length];
+
+ int hitUpto = 0;
+ while(hitUpto < hits.length) {
+ assert queue.size() > 0;
+ ShardRef ref = queue.pop();
+ hits[hitUpto] = shardHits[ref.shardIndex].scoreDocs[ref.hitIndex++];
+ shardIndex[hitUpto] = ref.shardIndex;
+
+ //System.out.println(" hitUpto=" + hitUpto);
+ //System.out.println(" doc=" + hits[hitUpto].doc + " score=" + hits[hitUpto].score);
+
+ hitUpto++;
+
+ if (ref.hitIndex < shardHits[ref.shardIndex].scoreDocs.length) {
+ // Not done with this these TopDocs yet:
+ queue.add(ref);
+ }
+ }
+
+ return new TopDocsAndShards(new TopDocs(totalHitCount, hits, maxScore),
+ shardIndex);
+ }
}
Index: lucene/src/test-framework/org/apache/lucene/index/RandomIndexWriter.java
--- lucene/src/test-framework/org/apache/lucene/index/RandomIndexWriter.java Fri Jun 10 16:56:32 2011 -0400
+++ lucene/src/test-framework/org/apache/lucene/index/RandomIndexWriter.java Fri Jun 10 19:12:55 2011 -0400
@@ -308,16 +308,24 @@
return getReader(true);
}
+ private boolean doRandomOptimize = true;
+
+ public void setDoRandomOptimize(boolean v) {
+ doRandomOptimize = v;
+ }
+
private void doRandomOptimize() throws IOException {
- final int segCount = w.getSegmentCount();
- if (r.nextBoolean() || segCount == 0) {
- // full optimize
- w.optimize();
- } else {
- // partial optimize
- final int limit = _TestUtil.nextInt(r, 1, segCount);
- w.optimize(limit);
- assert w.getSegmentCount() <= limit: "limit=" + limit + " actual=" + w.getSegmentCount();
+ if (doRandomOptimize) {
+ final int segCount = w.getSegmentCount();
+ if (r.nextBoolean() || segCount == 0) {
+ // full optimize
+ w.optimize();
+ } else {
+ // partial optimize
+ final int limit = _TestUtil.nextInt(r, 1, segCount);
+ w.optimize(limit);
+ assert w.getSegmentCount() <= limit: "limit=" + limit + " actual=" + w.getSegmentCount();
+ }
}
switchDoDocValues();
}
Index: lucene/src/test-framework/org/apache/lucene/util/LuceneTestCase.java
--- lucene/src/test-framework/org/apache/lucene/util/LuceneTestCase.java Fri Jun 10 16:56:32 2011 -0400
+++ lucene/src/test-framework/org/apache/lucene/util/LuceneTestCase.java Fri Jun 10 19:12:55 2011 -0400
@@ -1484,4 +1484,5 @@
@Ignore("just a hack")
public final void alwaysIgnoredTestMethod() {}
-}
+
+}
\ No newline at end of file
Index: lucene/src/test-framework/org/apache/lucene/util/_TestUtil.java
--- lucene/src/test-framework/org/apache/lucene/util/_TestUtil.java Fri Jun 10 16:56:32 2011 -0400
+++ lucene/src/test-framework/org/apache/lucene/util/_TestUtil.java Fri Jun 10 19:12:55 2011 -0400
@@ -27,10 +27,10 @@
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Random;
-import java.util.Map;
-import java.util.HashMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -46,6 +46,9 @@
import org.apache.lucene.index.TieredMergePolicy;
import org.apache.lucene.index.codecs.Codec;
import org.apache.lucene.index.codecs.CodecProvider;
+import org.apache.lucene.search.FieldDoc;
+import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.junit.Assert;
@@ -467,4 +470,24 @@
newName.append(suffix);
return new File(directory, newName.toString());
}
+
+ public static void assertEquals(TopDocs expected, TopDocs actual) {
+ Assert.assertEquals("wrong total hits", expected.totalHits, actual.totalHits);
+ Assert.assertEquals("wrong maxScore", expected.getMaxScore(), actual.getMaxScore(), 0.0);
+ Assert.assertEquals("wrong hit count", expected.scoreDocs.length, actual.scoreDocs.length);
+ for(int hitIDX=0;hitIDX {
@Override
public int compare(int slot1, int slot2) {
@@ -132,10 +132,15 @@
}
@Override
- public Comparable> value(int slot) {
+ public Object value(int slot) {
throw new UnsupportedOperationException(UNSUPPORTED_MSG);
}
-
+
+ @Override
+ public int compareValues(Object first, Object second) {
+ throw new UnsupportedOperationException(UNSUPPORTED_MSG);
+ }
+
}
static final class JustCompileFieldComparatorSource extends FieldComparatorSource {
Index: lucene/src/test/org/apache/lucene/search/TestElevationComparator.java
--- lucene/src/test/org/apache/lucene/search/TestElevationComparator.java Fri Jun 10 16:56:32 2011 -0400
+++ lucene/src/test/org/apache/lucene/search/TestElevationComparator.java Fri Jun 10 19:12:55 2011 -0400
@@ -139,7 +139,7 @@
@Override
public FieldComparator newComparator(final String fieldname, final int numHits, int sortPos, boolean reversed) throws IOException {
- return new FieldComparator() {
+ return new FieldComparator() {
FieldCache.DocTermsIndex idIndex;
private final int[] values = new int[numHits];
@@ -184,9 +184,16 @@
}
@Override
- public Comparable> value(int slot) {
+ public Integer value(int slot) {
return Integer.valueOf(values[slot]);
}
+
+ @Override
+ public int compareValues(Integer first, Integer second) {
+ // values will be small enough that there is no
+ // overflow concern
+ return first.intValue() - second.intValue();
+ }
};
}
}
Index: lucene/src/test/org/apache/lucene/search/TestSort.java
--- lucene/src/test/org/apache/lucene/search/TestSort.java Fri Jun 10 16:56:32 2011 -0400
+++ lucene/src/test/org/apache/lucene/search/TestSort.java Fri Jun 10 19:12:55 2011 -0400
@@ -511,7 +511,7 @@
assertMatches (empty, queryX, sort, "");
}
- static class MyFieldComparator extends FieldComparator {
+ static class MyFieldComparator extends FieldComparator {
int[] docValues;
int[] slotValues;
int bottomValue;
@@ -527,6 +527,7 @@
@Override
public int compare(int slot1, int slot2) {
+ // values are small enough that overflow won't happen
return slotValues[slot1] - slotValues[slot2];
}
@@ -553,9 +554,15 @@
}
@Override
- public Comparable> value(int slot) {
+ public Integer value(int slot) {
return Integer.valueOf(slotValues[slot]);
}
+
+ @Override
+ public int compareValues(Integer first, Integer second) {
+ // values are small enough that overflow won't happen
+ return first.intValue() - second.intValue();
+ }
}
static class MyFieldComparatorSource extends FieldComparatorSource {
Index: lucene/src/test/org/apache/lucene/search/TestTopDocsMerge.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ lucene/src/test/org/apache/lucene/search/TestTopDocsMerge.java Fri Jun 10 19:12:55 2011 -0400
@@ -0,0 +1,225 @@
+package org.apache.lucene.search;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.NumericField;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.RandomIndexWriter;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util._TestUtil;
+
+public class TestTopDocsMerge extends LuceneTestCase {
+
+ private static class ShardSearcher extends IndexSearcher {
+ private final IndexReader.AtomicReaderContext[] ctx;
+
+ public ShardSearcher(IndexReader.AtomicReaderContext ctx) {
+ super(ctx.parent);
+ this.ctx = new IndexReader.AtomicReaderContext[] {ctx};
+ }
+
+ public void search(Weight weight, Collector collector) throws IOException {
+ search(ctx, weight, null, collector);
+ }
+
+ public TopDocs search(Weight weight, int topN) throws IOException {
+ return search(ctx, weight, null, topN);
+ }
+ }
+
+ public void testSort() throws Exception {
+
+ IndexReader reader = null;
+ IndexReader[] subReaders = null;
+ Directory dir = null;
+
+ final int numDocs = atLeast(1000);
+ //final int numDocs = atLeast(50);
+
+ final String[] tokens = new String[] {"a", "b", "c", "d", "e"};
+
+ if (VERBOSE) {
+ System.out.println("TEST: make index");
+ }
+
+ // Iterate until we get an index with more than one segment:
+ while(true) {
+
+ dir = newDirectory();
+ final RandomIndexWriter w = new RandomIndexWriter(random, dir);
+ w.setDoRandomOptimize(false);
+
+ w.w.getConfig().setMaxBufferedDocs(atLeast(100));
+
+ final String[] content = new String[atLeast(20)];
+
+ for(int contentIDX=0;contentIDX sortFields = new ArrayList();
+ sortFields.add(new SortField("string", SortField.STRING, true));
+ sortFields.add(new SortField("string", SortField.STRING, false));
+ sortFields.add(new SortField("int", SortField.INT, true));
+ sortFields.add(new SortField("int", SortField.INT, false));
+ sortFields.add(new SortField("float", SortField.FLOAT, true));
+ sortFields.add(new SortField("float", SortField.FLOAT, false));
+ sortFields.add(new SortField(null, SortField.SCORE, true));
+ sortFields.add(new SortField(null, SortField.SCORE, false));
+ sortFields.add(new SortField(null, SortField.DOC, true));
+ sortFields.add(new SortField(null, SortField.DOC, false));
+
+ for(int iter=0;iter<1000*RANDOM_MULTIPLIER;iter++) {
+
+ // TODO: custom FieldComp...
+ final Query query = new TermQuery(new Term("text", tokens[random.nextInt(tokens.length)]));
+
+ final Sort sort;
+ if (random.nextInt(10) == 4) {
+ // Sort by score
+ sort = null;
+ } else {
+ final SortField[] randomSortFields = new SortField[_TestUtil.nextInt(random, 1, 3)];
+ for(int sortIDX=0;sortIDX