Index: lucene/src/java/org/apache/lucene/search/MultiPhraseQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/MultiPhraseQuery.java (revision 1097776) +++ lucene/src/java/org/apache/lucene/search/MultiPhraseQuery.java (working copy) @@ -214,7 +214,7 @@ docFreq = reader.docFreq(term.field(), term.bytes()); } - postingsFreqs[pos] = new PhraseQuery.PostingsAndFreq(postingsEnum, docFreq, positions.get(pos).intValue()); + postingsFreqs[pos] = new PhraseQuery.PostingsAndFreq(postingsEnum, docFreq, positions.get(pos).intValue(), terms[0]); } // sort by increasing docFreq order Index: lucene/src/java/org/apache/lucene/search/PhraseQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/PhraseQuery.java (revision 1097776) +++ lucene/src/java/org/apache/lucene/search/PhraseQuery.java (working copy) @@ -124,16 +124,48 @@ final DocsAndPositionsEnum postings; final int docFreq; final int position; + final Term term; - public PostingsAndFreq(DocsAndPositionsEnum postings, int docFreq, int position) { + public PostingsAndFreq(DocsAndPositionsEnum postings, int docFreq, int position, Term term) { this.postings = postings; this.docFreq = docFreq; this.position = position; + this.term = term; } public int compareTo(PostingsAndFreq other) { + if (docFreq == other.docFreq) { + if (position == other.position) { + return term.compareTo(other.term); + } + return position - other.position; + } return docFreq - other.docFreq; } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + docFreq; + result = prime * result + position; + result = prime * result + ((term == null) ? 0 : term.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + PostingsAndFreq other = (PostingsAndFreq) obj; + if (docFreq != other.docFreq) return false; + if (position != other.position) return false; + if (term == null) { + if (other.term != null) return false; + } else if (!term.equals(other.term)) return false; + return true; + } } private class PhraseWeight extends Weight { @@ -197,7 +229,7 @@ return null; } } - postingsFreqs[i] = new PostingsAndFreq(postingsEnum, reader.docFreq(t.field(), t.bytes()), positions.get(i).intValue()); + postingsFreqs[i] = new PostingsAndFreq(postingsEnum, reader.docFreq(t.field(), t.bytes()), positions.get(i).intValue(), t); } // sort by increasing docFreq order Index: lucene/src/java/org/apache/lucene/util/ArrayUtil.java =================================================================== --- lucene/src/java/org/apache/lucene/util/ArrayUtil.java (revision 1097776) +++ lucene/src/java/org/apache/lucene/util/ArrayUtil.java (working copy) @@ -17,8 +17,12 @@ * limitations under the License. */ +import java.lang.reflect.Array; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; +import java.util.List; /** * Methods for manipulating arrays. @@ -565,6 +569,7 @@ public static void quickSort(T[] a, int fromIndex, int toIndex, Comparator comp) { if (toIndex-fromIndex <= 1) return; getSorter(a, comp).quickSort(fromIndex, toIndex-1); + assert saneComparator(a, fromIndex, toIndex, comp); } /** @@ -584,6 +589,7 @@ public static > void quickSort(T[] a, int fromIndex, int toIndex) { if (toIndex-fromIndex <= 1) return; getSorter(a).quickSort(fromIndex, toIndex-1); + assert saneComparator(a, fromIndex, toIndex, null); } /** @@ -594,6 +600,37 @@ quickSort(a, 0, a.length); } + private static boolean saneComparator(T[] a, int fromIndex, int toIndex, Comparator comp) { + T[] a2 = copyOfRange(a, fromIndex, toIndex); + List a2l = Arrays.asList(a2); + Collections.reverse(a2l); + a2 = a2l.toArray(a2); + if (comp != null) { + Arrays.sort(a2, 0, a2.length, comp); + } else { + Arrays.sort(a2, 0, a2.length); + } + for (int i = 0; i < a2.length; i++) { + assert a2[i].equals(a[fromIndex+i]) : "insane comparator for: " + a.getClass().getComponentType().getName(); + } + return true; + } + + // apache harmony copyfRange + @SuppressWarnings("unchecked") + public static T[] copyOfRange(T[] original, int start, int end) { + if (original.length >= start && 0 <= start) { + if (start <= end) { + int length = end - start; + int copyLength = Math.min(length, original.length - start); + T[] copy = (T[]) Array.newInstance(original.getClass().getComponentType(), length); + System.arraycopy(original, start, copy, 0, copyLength); + return copy; + } + throw new IllegalArgumentException(); + } + throw new ArrayIndexOutOfBoundsException(); + } // mergeSorts: /** @@ -605,6 +642,7 @@ public static void mergeSort(T[] a, int fromIndex, int toIndex, Comparator comp) { if (toIndex-fromIndex <= 1) return; getSorter(a, comp).mergeSort(fromIndex, toIndex-1); + assert saneComparator(a, fromIndex, toIndex, comp); } /** @@ -624,6 +662,7 @@ public static > void mergeSort(T[] a, int fromIndex, int toIndex) { if (toIndex-fromIndex <= 1) return; getSorter(a).mergeSort(fromIndex, toIndex-1); + assert saneComparator(a, fromIndex, toIndex, null); } /** @@ -645,6 +684,7 @@ public static void insertionSort(T[] a, int fromIndex, int toIndex, Comparator comp) { if (toIndex-fromIndex <= 1) return; getSorter(a, comp).insertionSort(fromIndex, toIndex-1); + assert saneComparator(a, fromIndex, toIndex, comp); } /** @@ -664,6 +704,7 @@ public static > void insertionSort(T[] a, int fromIndex, int toIndex) { if (toIndex-fromIndex <= 1) return; getSorter(a).insertionSort(fromIndex, toIndex-1); + assert saneComparator(a, fromIndex, toIndex, null); } /**