The core Query classes

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 lucene-core 10.x and the companion modules. Some areas (the Panama foreign-memory / Vector API internals, codec file-format internals, and the nightly benchmark harness) are linked, not documented in depth.

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.

Every search in Lucene executes a Query. The query parsers just assemble these objects; building them directly is the norm for anything an application generates. This page is a tour of the concrete Query subclasses in the org.apache.lucene.search package, grouped by what they do.

TermQuery — the atom

Matches documents containing one exact term in one field. The term value is not analyzed, so it must already be in indexed form (lower-cased, folded, stemmed — whatever the field’s analyzer produced).

// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/search/TermQuery.html
Query q = new TermQuery(new Term("status", "published"));

BooleanQuery.Builder — combining clauses

Clauses are added with a BooleanClause.Occur:

Occur Meaning

MUST

Must match; contributes to the score.

SHOULD

Optional; contributes to the score. If a query has only SHOULD clauses, at least one must match (unless overridden).

FILTER

Must match; does not contribute to the score (cacheable). The modern name — there is no Occur.Filter.

MUST_NOT

Must not match; no score effect.

setMinimumNumberShouldMatch(n) requires at least n of the SHOULD clauses when MUST/FILTER clauses are also present. A BooleanQuery may hold at most IndexSearcher.getMaxClauseCount() clauses — 1024 by default, and the same ceiling applies to the clause count a multi-term query expands into.

// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/search/BooleanQuery.html
Query bq = new BooleanQuery.Builder()
    .add(new TermQuery(new Term("body", "lucene")), BooleanClause.Occur.MUST)
    .add(new TermQuery(new Term("body", "search")), BooleanClause.Occur.SHOULD)
    .add(new TermQuery(new Term("body", "server")), BooleanClause.Occur.SHOULD)
    .add(new TermQuery(new Term("lang", "en")),     BooleanClause.Occur.FILTER)
    .add(new TermQuery(new Term("status", "draft")), BooleanClause.Occur.MUST_NOT)
    .setMinimumNumberShouldMatch(1)
    .build();

IndexSearcher.setMaxClauseCount(4096);   // static; raise with care, it guards memory

Phrase queries

PhraseQuery.Builder matches an ordered sequence of terms within slop position edits (slop=0 is exact adjacency). Per-term position offsets support gaps. MultiPhraseQuery allows a set of alternative terms at one position — the query-time equivalent of a synonym at that slot.

// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/search/PhraseQuery.html
Query pq = new PhraseQuery.Builder()
    .add(new Term("title", "quick"))
    .add(new Term("title", "fox"), 2)     // "quick ? fox"
    .setSlop(1)
    .build();

// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/search/MultiPhraseQuery.html
Query mpq = new MultiPhraseQuery.Builder()
    .add(new Term("title", "quick"))
    .add(new Term[] { new Term("title", "fox"), new Term("title", "hound") })
    .build();

For richer positional logic see Interval & span queries.

Multi-term queries

All four enumerate the term dictionary and rewrite to a BooleanQuery (or a ConstantScore variant); each is subject to the clause-count ceiling.

// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/search/PrefixQuery.html
Query prefix = new PrefixQuery(new Term("name", "lucen"));

// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/search/WildcardQuery.html
Query wild = new WildcardQuery(new Term("name", "l?cen*"));   // ? one char, * any run

// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/search/RegexpQuery.html
Query re = new RegexpQuery(new Term("name", "luc[e]+ne"));    // Lucene regex flavour, anchored

// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/search/FuzzyQuery.html
Query fuzzy = new FuzzyQuery(new Term("name", "lucene"), 2, 1);
// maxEdits 0..2 (Levenshtein automaton), prefixLength 1 exact leading char to bound expansion

TermRangeQuery

A byte-ordered range over a string/KeywordField term dictionary. It does not understand numbers or dates — use point range queries (IntPoint.newRangeQuery, LongPoint.newRangeQuery, …​) for those.

// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/search/TermRangeQuery.html
Query range = TermRangeQuery.newStringRange("city", "Amsterdam", "Berlin", true, false);
// lower inclusive, upper exclusive; null bound = open-ended

Match-all and wrappers

// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/search/MatchAllDocsQuery.html
Query all = new MatchAllDocsQuery();     // every live doc, constant score 1.0

// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/search/ConstantScoreQuery.html
Query cs = new ConstantScoreQuery(new PrefixQuery(new Term("name", "lucen")));

// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/search/BoostQuery.html
Query boosted = new BoostQuery(new TermQuery(new Term("title", "lucene")), 3.0f);

// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/search/DisjunctionMaxQuery.html
Query dm = new DisjunctionMaxQuery(
    List.of(new TermQuery(new Term("title", "lucene")),
            new TermQuery(new Term("body",  "lucene"))),
    0.3f);   // score = max(subscores) + tieBreaker * sum(other subscores)

DisjunctionMaxQuery is the right tool for "same term, several fields" — it rewards the single best field rather than summing, which a SHOULD BooleanQuery would do.

TermInSetQuery

One field, many acceptable exact values — far cheaper than a BooleanQuery of hundreds of TermQuery SHOULD clauses, and not bound by the clause-count limit. Constant-scoring.

// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/search/TermInSetQuery.html
Query inSet = new TermInSetQuery("tag",
    List.of(new BytesRef("java"), new BytesRef("search"), new BytesRef("lucene")));

QueryVisitor and rewriting

Query.visit(QueryVisitor) walks a query tree without executing it — the supported way to extract terms (for highlighting), inspect structure, or transform a query. Override consumeTerms, getSubVisitor, and friends.

// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/search/QueryVisitor.html
Set<Term> terms = new HashSet<>();
query.visit(new QueryVisitor() {
    @Override
    public void consumeTerms(Query q, Term... ts) { Collections.addAll(terms, ts); }
});

Rewriting — expanding a PrefixQuery/WildcardQuery/FuzzyQuery against the actual term dictionary — now goes through IndexSearcher: query.rewrite(indexSearcher) in 10.x, where older code called query.rewrite(indexReader). IndexSearcher.rewrite is applied for you before a search; call it explicitly only when you need the concrete rewritten form.