diff --git a/lucene/queries/src/java/org/apache/lucene/queries/intervals/DisjunctionIntervalsSource.java b/lucene/queries/src/java/org/apache/lucene/queries/intervals/DisjunctionIntervalsSource.java index 6bb9a397f9e..7e1a701d739 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/intervals/DisjunctionIntervalsSource.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/intervals/DisjunctionIntervalsSource.java @@ -120,7 +120,10 @@ class DisjunctionIntervalsSource extends IntervalsSource { @Override public String toString() { - return subSources.stream().map(Object::toString).collect(Collectors.joining(",", "or(", ")")); + return subSources.stream() + .map(Object::toString) + .sorted() + .collect(Collectors.joining(",", "or(", ")")); } @Override diff --git a/lucene/queries/src/test/org/apache/lucene/queries/intervals/TestIntervals.java b/lucene/queries/src/test/org/apache/lucene/queries/intervals/TestIntervals.java index 57e86f831b9..3575ed4a5af 100644 --- a/lucene/queries/src/test/org/apache/lucene/queries/intervals/TestIntervals.java +++ b/lucene/queries/src/test/org/apache/lucene/queries/intervals/TestIntervals.java @@ -19,6 +19,7 @@ package org.apache.lucene.queries.intervals; import java.io.IOException; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; @@ -401,6 +402,35 @@ public class TestIntervals extends LuceneTestCase { source, "field1", 3, new int[][] {{}, {0, 3, 2, 6}, {3, 6}, {}, {0, 3, 2, 6}, {}}); } + public void testIntervalDisjunctionToStringStability() { + /* + Sanity check that the subclauses of a disjunction are presented in sorted order via the toString() method. + The exact order is irrelevant, but ensuring stability of output makes the output more useful; e.g., for external + comparison across different JVMs, etc... + */ + final int size = + random().nextInt(22) + 4; // ensure a reasonably large minimum number of clauses + final String[] terms = new String[size]; + for (int i = 0; i < size; i++) { + terms[i] = Character.toString((char) ('a' + i)); + } + final String expected = Arrays.stream(terms).collect(Collectors.joining(",", "or(", ")")); + + /* + NOTE: shuffling below shouldn't matter at the moment (because the disjunction subSources are destined for a + HashMap, so will be reordered anyway); but it might matter if the internal implementation of + DisjunctionIntervalsSource changes. + */ + Collections.shuffle(Arrays.asList(terms), random()); + + IntervalsSource source = + Intervals.or( + Arrays.stream(terms) + .map((term) -> Intervals.term(term)) + .toArray((sz) -> new IntervalsSource[sz])); + assertEquals(expected, source.toString()); + } + public void testIntervalDisjunction() throws IOException { IntervalsSource source = Intervals.or(Intervals.term("pease"), Intervals.term("hot"), Intervals.term("notMatching"));