diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 023c1733b31..df42fd88a93 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -8,6 +8,9 @@ http://s.apache.org/luceneversions
API Changes
---------------------
+* GITHUB#13859: Allow open-ended ranges in Intervals range queries. (Mayya Sharipova)
+
+
New Features
---------------------
(No changes)
diff --git a/lucene/queries/src/java/org/apache/lucene/queries/intervals/Intervals.java b/lucene/queries/src/java/org/apache/lucene/queries/intervals/Intervals.java
index 57d5674b254..e3808f406cf 100644
--- a/lucene/queries/src/java/org/apache/lucene/queries/intervals/Intervals.java
+++ b/lucene/queries/src/java/org/apache/lucene/queries/intervals/Intervals.java
@@ -247,8 +247,10 @@ public final class Intervals {
* Return an {@link IntervalsSource} over the disjunction of all terms that fall within the given
* range
*
- * @param lowerTerm The term text at the lower end of the range
- * @param upperTerm The term text at the upper end of the range
+ * @param lowerTerm The term text at the lower end of the range; can be {@code null} to indicate
+ * an open-ended range at this end
+ * @param upperTerm The term text at the upper end of the range; can be {@code null} to indicate
+ * an open-ended range at this end
* @param includeLower If true, the lowerTerm
is included in the range
* @param includeUpper If true, the upperTerm
is included in the range
* @throws IllegalStateException if the range expands to more than {@link #DEFAULT_MAX_EXPANSIONS}
@@ -266,8 +268,10 @@ public final class Intervals {
*
WARNING: Setting {@code maxExpansions} to higher than the default value of {@link
* #DEFAULT_MAX_EXPANSIONS} can be both slow and memory-intensive
*
- * @param lowerTerm The term text at the lower end of the range
- * @param upperTerm The term text at the upper end of the range
+ * @param lowerTerm The term text at the lower end of the range; can be {@code null} to indicate
+ * an open-ended range at this end
+ * @param upperTerm The term text at the upper end of the range; can be {@code null} to indicate
+ * an open-ended range at this end
* @param includeLower If true, the lowerTerm
is included in the range
* @param includeUpper If true, the upperTerm
is included in the range
* @param maxExpansions the maximum number of terms to expand to
@@ -286,9 +290,9 @@ public final class Intervals {
StringBuilder buffer = new StringBuilder();
buffer.append("{");
- buffer.append(lowerTerm.utf8ToString());
+ buffer.append(lowerTerm == null ? "* " : lowerTerm.utf8ToString());
buffer.append(",");
- buffer.append(upperTerm.utf8ToString());
+ buffer.append(upperTerm == null ? "*" : upperTerm.utf8ToString());
buffer.append("}");
return new MultiTermIntervalsSource(ca, maxExpansions, buffer.toString());
}
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 43fd8fb7fb8..3d9560858ac 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
@@ -1138,6 +1138,46 @@ public class TestIntervals extends LuceneTestCase {
checkVisits(source, 1);
}
+ public void testOpenEndedRange() throws IOException {
+ {
+ IntervalsSource source = Intervals.range(new BytesRef("porridge"), null, false, false);
+ checkIntervals(
+ source,
+ "field1",
+ 5,
+ new int[][] {
+ {3, 3},
+ {9, 9, 10, 10, 14, 14, 18, 18, 22, 22, 26, 26, 27, 27},
+ {9, 9, 10, 10, 11, 11, 14, 14, 18, 18, 22, 22, 26, 26},
+ {8, 8},
+ {9, 9, 10, 10, 12, 12, 14, 14, 18, 18, 21, 21},
+ {}
+ });
+ MatchesIterator mi = getMatches(source, 3, "field1");
+ assertNotNull(mi);
+ assertMatch(mi, 8, 8, 37, 41);
+ }
+
+ {
+ IntervalsSource source = Intervals.range(null, new BytesRef("anyone"), false, true);
+ checkIntervals(
+ source,
+ "field1",
+ 1,
+ new int[][] {
+ {4, 4},
+ {},
+ {},
+ {},
+ {},
+ {}
+ });
+ MatchesIterator mi = getMatches(source, 0, "field1");
+ assertNotNull(mi);
+ assertMatch(mi, 4, 4, 23, 29);
+ }
+ }
+
public void testWrappedFilters() throws IOException {
IntervalsSource source =
Intervals.or(