Interval & span queries
|
This section documents the current Apache Lucene 10.x line — Lucene 10 requires Java 21 — as published
at the Apache Lucene documentation and Javadoc, which is the reference these
pages are written and verified against. No specific patch version is pinned; examples target This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production, as Lucene iterates quickly. This section’s bibliography lists the reference material consulted while preparing these pages. |
Proximity matching — "these terms, near each other, in this order, but not when a third term sits
between them" — is expressed in modern Lucene with the Intervals API: composable
IntervalsSource factory methods wrapped in a single IntervalQuery. It replaces the older
SpanQuery family with a smaller, nestable vocabulary that reads closer to the question being asked.
The Intervals / IntervalQuery API
org.apache.lucene.queries.intervals.Intervals is a factory of static methods that each build an
IntervalsSource; IntervalQuery(field, source) turns one into a runnable Query scoped to a
single analyzed field. Sources nest freely, so a complex proximity constraint is built up from small
parts rather than a deep tree of span classes.
| Factory | Matches an interval that… |
|---|---|
|
is a single occurrence of term |
|
is |
|
contains |
|
contains both |
|
is |
|
is |
|
is |
|
is |
|
is |
|
is |
|
is |
See the
org.apache.lucene.queries.intervals
package Javadoc for the full list (it also covers atLeast, wildcard, prefix, regexp,
fixField, extend, and the IntervalFunction combinators). The module ships in lucene-queries:
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queries</artifactId>
<version>10.0.0</version>
</dependency>
A worked proximity example
Find documents where "quick" and "fox" occur within three positions of each other, in that order, but only when "lazy" does not appear between them:
// https://lucene.apache.org/core/10_0_0/queries/org/apache/lucene/queries/intervals/Intervals.html
import org.apache.lucene.queries.intervals.Intervals;
import org.apache.lucene.queries.intervals.IntervalQuery;
import org.apache.lucene.queries.intervals.IntervalsSource;
import org.apache.lucene.search.Query;
IntervalsSource near =
Intervals.maxgaps(3,
Intervals.ordered(
Intervals.term("quick"),
Intervals.term("fox")));
IntervalsSource clean =
Intervals.notContaining(near, Intervals.term("lazy"));
Query q = new IntervalQuery("body", clean);
Because the field is analyzed, pass already-analyzed term text (lowercased here to match a
StandardAnalyzer index). Combine an IntervalQuery with ordinary clauses through
BooleanQuery.Builder the same way as any other Query:
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
Query combined = new BooleanQuery.Builder()
.add(new IntervalQuery("body", clean), Occur.MUST)
.add(org.apache.lucene.document.IntPoint.newRangeQuery("year", 1990, 2000), Occur.FILTER)
.build();
IntervalQuery scores with the active Similarity using the matched interval’s frequency and
width, so tighter matches score higher without a custom scorer. Its Matches support also makes it
work directly with the highlighters — see
Highlighting, suggesters & more.
The legacy SpanQuery family
Before Intervals, positional matching used SpanQuery: SpanTermQuery, SpanNearQuery,
SpanOrQuery, SpanNotQuery, SpanContainingQuery, SpanPositionRangeQuery, and
FieldMaskingSpanQuery — see the
org.apache.lucene.queries.spans
package Javadoc. These classes still exist for backward compatibility and for a few edge cases
the Intervals API does not cover, but new code should use Intervals — it is faster to evaluate,
composes without the payload/position bookkeeping, and expresses the common "within N, not
containing X" shapes directly.