Index: modules/grouping/src/test/org/apache/lucene/search/grouping/TestGrouping.java =================================================================== --- modules/grouping/src/test/org/apache/lucene/search/grouping/TestGrouping.java (revision 1136080) +++ modules/grouping/src/test/org/apache/lucene/search/grouping/TestGrouping.java (working copy) @@ -876,13 +876,11 @@ private void verifyShards(int[] docStarts, TopGroups topGroups) { for(GroupDocs group : topGroups.groups) { - assertTrue(group instanceof GroupDocsAndShards); - GroupDocsAndShards withShards = (GroupDocsAndShards) group; - for(int hitIDX=0;hitIDX= mergedTopDocs.scoreDocs.length) { mergedScoreDocs = new ScoreDoc[0]; - mergedShardIndex = new int[0]; } else { mergedScoreDocs = new ScoreDoc[mergedTopDocs.scoreDocs.length - docOffset]; System.arraycopy(mergedTopDocs.scoreDocs, @@ -151,20 +147,13 @@ mergedScoreDocs, 0, mergedTopDocs.scoreDocs.length - docOffset); - mergedShardIndex = new int[mergedTopDocs.scoreDocs.length - docOffset]; - System.arraycopy(mergedTopDocs.shardIndex, - docOffset, - mergedShardIndex, - 0, - mergedTopDocs.scoreDocs.length - docOffset); } //System.out.println("SHARDS=" + Arrays.toString(mergedTopDocs.shardIndex)); - mergedGroupDocs[groupIDX] = new GroupDocsAndShards(maxScore, - totalHits, - mergedScoreDocs, - groupValue, - shardGroups[0].groups[groupIDX].groupSortValues, - mergedShardIndex); + mergedGroupDocs[groupIDX] = new GroupDocs(maxScore, + totalHits, + mergedScoreDocs, + groupValue, + shardGroups[0].groups[groupIDX].groupSortValues); } return new TopGroups(groupSort.getSort(), Index: modules/grouping/src/java/org/apache/lucene/search/grouping/GroupDocsAndShards.java =================================================================== --- modules/grouping/src/java/org/apache/lucene/search/grouping/GroupDocsAndShards.java (revision 1136079) +++ modules/grouping/src/java/org/apache/lucene/search/grouping/GroupDocsAndShards.java (working copy) @@ -1,36 +0,0 @@ -package org.apache.lucene.search.grouping; - -/** - * 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 org.apache.lucene.search.ScoreDoc; - -public class GroupDocsAndShards extends GroupDocs { - - public final int[] shardIndex; - - public GroupDocsAndShards(float maxScore, - int totalHits, - ScoreDoc[] scoreDocs, - GROUP_VALUE_TYPE groupValue, - Object[] groupSortValues, - int[] shardIndex) { - super(maxScore, totalHits, scoreDocs, groupValue, groupSortValues); - this.shardIndex = shardIndex; - } -} - Index: lucene/src/test/org/apache/lucene/search/TestTopDocsMerge.java =================================================================== --- lucene/src/test/org/apache/lucene/search/TestTopDocsMerge.java (revision 1136080) +++ lucene/src/test/org/apache/lucene/search/TestTopDocsMerge.java (working copy) @@ -223,7 +223,7 @@ } // Merge: - final TopDocs.TopDocsAndShards mergedHits = TopDocs.merge(sort, numHits, shardHits); + final TopDocs mergedHits = TopDocs.merge(sort, numHits, shardHits); if (mergedHits.scoreDocs != null) { // Make sure the returned shards are correct: @@ -231,7 +231,7 @@ final ScoreDoc sd = mergedHits.scoreDocs[hitIDX]; assertEquals("doc=" + sd.doc + " wrong shard", ReaderUtil.subIndex(sd.doc, docStarts), - mergedHits.shardIndex[hitIDX]); + sd.shardIndex); } } Index: lucene/src/java/org/apache/lucene/search/FieldDoc.java =================================================================== --- lucene/src/java/org/apache/lucene/search/FieldDoc.java (revision 1136080) +++ lucene/src/java/org/apache/lucene/search/FieldDoc.java (working copy) @@ -49,16 +49,22 @@ public Object[] fields; /** Expert: Creates one of these objects with empty sort information. */ - public FieldDoc (int doc, float score) { + public FieldDoc(int doc, float score) { super (doc, score); } /** Expert: Creates one of these objects with the given sort information. */ - public FieldDoc (int doc, float score, Object[] fields) { + public FieldDoc(int doc, float score, Object[] fields) { super (doc, score); this.fields = fields; } + /** Expert: Creates one of these objects with the given sort information. */ + public FieldDoc(int doc, float score, Object[] fields, int shardIndex) { + super (doc, score, shardIndex); + this.fields = fields; + } + // A convenience method for debugging. @Override public String toString() { Index: lucene/src/java/org/apache/lucene/search/TopDocs.java =================================================================== --- lucene/src/java/org/apache/lucene/search/TopDocs.java (revision 1136080) +++ lucene/src/java/org/apache/lucene/search/TopDocs.java (working copy) @@ -25,11 +25,13 @@ * IndexSearcher#search(Query,Filter,int)} and {@link * IndexSearcher#search(Query,int)}. */ public class TopDocs { - /** The total number of hits for the query. - */ + + /** The total number of hits for the query. */ public int totalHits; + /** The top hits for the query. */ public ScoreDoc[] scoreDocs; + /** Stores the maximum score value encountered, needed for normalizing. */ private float maxScore; @@ -38,12 +40,12 @@ * scores are not tracked, this returns {@link Float#NaN}. */ public float getMaxScore() { - return maxScore; + return maxScore; } /** Sets the maximum score value encountered. */ public void setMaxScore(float maxScore) { - this.maxScore=maxScore; + this.maxScore=maxScore; } /** Constructs a TopDocs with a default maxScore=Float.NaN. */ @@ -189,22 +191,6 @@ } } - /** 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 extends TopDocs { - - /** Parallel array matching hits.scoreDocs */ - public final int[] shardIndex; - - public TopDocsAndShards(int totalHits, ScoreDoc[] scoreDocs, float maxScore, int[] shardIndex) { - super(totalHits, scoreDocs, maxScore); - 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 @@ -216,7 +202,7 @@ *

Pass sort=null to merge sort by score descending. * * @lucene.experimental */ - public static TopDocsAndShards merge(Sort sort, int topN, TopDocs[] shardHits) throws IOException { + public static TopDocs merge(Sort sort, int topN, TopDocs[] shardHits) throws IOException { final PriorityQueue queue; if (sort == null) { @@ -238,14 +224,17 @@ } 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; + final ScoreDoc hit = shardHits[ref.shardIndex].scoreDocs[ref.hitIndex++]; + if (sort == null) { + hits[hitUpto] = new ScoreDoc(hit.doc, hit.score, ref.shardIndex); + } else { + hits[hitUpto] = new FieldDoc(hit.doc, hit.score, ((FieldDoc) hit).fields, ref.shardIndex); + } //System.out.println(" hitUpto=" + hitUpto); //System.out.println(" doc=" + hits[hitUpto].doc + " score=" + hits[hitUpto].score); @@ -258,6 +247,10 @@ } } - return new TopDocsAndShards(totalHitCount, hits, maxScore, shardIndex); + if (sort == null) { + return new TopDocs(totalHitCount, hits, maxScore); + } else { + return new TopFieldDocs(totalHitCount, hits, sort.getSort(), maxScore); + } } } Index: lucene/src/java/org/apache/lucene/search/FieldComparator.java =================================================================== --- lucene/src/java/org/apache/lucene/search/FieldComparator.java (revision 1136080) +++ lucene/src/java/org/apache/lucene/search/FieldComparator.java (working copy) @@ -954,6 +954,19 @@ public BytesRef value(int slot) { return TermOrdValComparator.this.value(slot); } + + @Override + public int compareValues(BytesRef val1, BytesRef val2) { + if (val1 == null) { + if (val2 == null) { + return 0; + } + return -1; + } else if (val2 == null) { + return 1; + } + return val1.compareTo(val2); + } } // Used per-segment when bit width of doc->ord is 8: @@ -1332,6 +1345,19 @@ public BytesRef value(int slot) { return values[slot]; } + + @Override + public int compareValues(BytesRef val1, BytesRef val2) { + if (val1 == null) { + if (val2 == null) { + return 0; + } + return -1; + } else if (val2 == null) { + return 1; + } + return val1.compareTo(val2); + } } final protected static int binarySearch(BytesRef br, DocTermsIndex a, BytesRef key) { Index: lucene/src/java/org/apache/lucene/search/ScoreDoc.java =================================================================== --- lucene/src/java/org/apache/lucene/search/ScoreDoc.java (revision 1136079) +++ lucene/src/java/org/apache/lucene/search/ScoreDoc.java (working copy) @@ -17,21 +17,30 @@ * limitations under the License. */ -/** Expert: Returned by low-level search implementations. - * @see TopDocs */ +/** Holds one hit in {@link TopDocs}. */ + public class ScoreDoc { - /** Expert: The score of this document for the query. */ + + /** The score of this document for the query. */ public float score; - /** Expert: A hit document's number. - * @see IndexSearcher#doc(int) - */ + /** A hit document's number. + * @see IndexSearcher#doc(int) */ public int doc; - /** Expert: Constructs a ScoreDoc. */ + /** Only set by {@link TopDocs#merge} */ + public int shardIndex; + + /** Constructs a ScoreDoc. */ public ScoreDoc(int doc, float score) { + this(doc, score, -1); + } + + /** Constructs a ScoreDoc. */ + public ScoreDoc(int doc, float score, int shardIndex) { this.doc = doc; this.score = score; + this.shardIndex = shardIndex; } // A convenience method for debugging. @@ -39,5 +48,4 @@ public String toString() { return "doc=" + doc + " score=" + score; } - }