Skip to main content
Lucene provides a rich set of query classes. All extend org.apache.lucene.search.Query and can be combined with BooleanQuery. The sections below describe each type, when to reach for it, and how to construct it.
Matches documents that contain an exact term in a specified field. It is the simplest and most efficient query type.
import org.apache.lucene.index.Term;
import org.apache.lucene.search.TermQuery;

// Match documents where the "status" field contains the term "published"
TermQuery query = new TermQuery(new Term("status", "published"));
TermQuery matches the literal byte value stored in the index. If the field was analyzed at index time, you must use the same analyzed form (e.g. lowercased) as the search term.
Combines multiple sub-queries using Boolean logic. Each clause carries an Occur value:
OccurMeaning
MUSTThe clause must match. Contributes to the score.
SHOULDThe clause may match. Contributes to the score when it does.
MUST_NOTThe clause must not match. Does not contribute to the score.
FILTERThe clause must match but does not contribute to the score.
Use BooleanQuery.Builder to assemble clauses:
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.index.Term;

BooleanQuery query = new BooleanQuery.Builder()
    .add(new TermQuery(new Term("category", "java")),   BooleanClause.Occur.MUST)
    .add(new TermQuery(new Term("body", "streams")),    BooleanClause.Occur.SHOULD)
    .add(new TermQuery(new Term("status", "deleted")),  BooleanClause.Occur.MUST_NOT)
    .build();
To require a minimum number of SHOULD clauses to match, call setMinimumNumberShouldMatch:
BooleanQuery query = new BooleanQuery.Builder()
    .add(new TermQuery(new Term("tag", "java")),   BooleanClause.Occur.SHOULD)
    .add(new TermQuery(new Term("tag", "jvm")),    BooleanClause.Occur.SHOULD)
    .add(new TermQuery(new Term("tag", "lucene")), BooleanClause.Occur.SHOULD)
    .setMinimumNumberShouldMatch(2)
    .build();
The default maximum clause count is 1,024. Attempting to add more clauses throws IndexSearcher.TooManyClauses. Increase the limit with IndexSearcher.setMaxClauseCount(int).
PhraseQuery matches documents that contain a sequence of terms in order, with an optional slop (number of allowed intervening positions).
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.index.Term;

// Exact phrase "quick brown"
PhraseQuery exact = new PhraseQuery("body", "quick", "brown");

// Slop of 1 allows one position between the terms
PhraseQuery sloppy = new PhraseQuery.Builder()
    .add(new Term("body", "quick"))
    .add(new Term("body", "fox"))
    .setSlop(1)
    .build();
MultiPhraseQuery allows multiple alternative terms at one or more positions, which is useful for synonyms:
import org.apache.lucene.search.MultiPhraseQuery;

MultiPhraseQuery query = new MultiPhraseQuery.Builder()
    .add(new Term[] {
        new Term("body", "fast"),
        new Term("body", "quick")    // synonym at position 0
    })
    .add(new Term("body", "brown"))  // position 1
    .build();
Matches terms within a given edit distance (Damerau-Levenshtein) of the target term. Useful for handling typos.
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.index.Term;

// maxEdits=2, prefixLength=1, maxExpansions=50 (defaults)
FuzzyQuery query = new FuzzyQuery(new Term("body", "lucene"), 2);

// With a required common prefix of 2 characters
FuzzyQuery prefixed = new FuzzyQuery(
    new Term("body", "lucene"),
    2,   // maxEdits
    2,   // prefixLength — first 2 chars must match exactly
    50,  // maxExpansions
    true // transpositions (Damerau vs Levenshtein)
);
Lucene supports at most 2 edits (LevenshteinAutomata.MAXIMUM_SUPPORTED_DISTANCE). Terms shorter than 3 characters are unlikely to match because the minimum term length is used to bound the allowed edit distance.
Matches terms using ? (single character) and * (zero or more characters) wildcards.
import org.apache.lucene.search.WildcardQuery;
import org.apache.lucene.index.Term;

// Matches "lucene", "lucency", "lucent", etc.
WildcardQuery query = new WildcardQuery(new Term("body", "luce*"));

// Matches "color" and "colour"
WildcardQuery query2 = new WildcardQuery(new Term("body", "colo?r"));
Leading wildcards (*ene) force a full term dictionary scan and can be very slow on large indexes. Where possible, prefer PrefixQuery or indexed n-grams instead.
Matches all terms that begin with a given prefix. More efficient than a leading-wildcard WildcardQuery.
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.index.Term;

// Matches "java", "javascript", "javadoc", etc.
PrefixQuery query = new PrefixQuery(new Term("language", "java"));
Matches all terms in a field that fall within a lexicographic range. Suitable for string fields (e.g. dates stored as yyyyMMdd strings).
import org.apache.lucene.search.TermRangeQuery;
import org.apache.lucene.util.BytesRef;

// Matches terms from "20240101" to "20241231", both inclusive
TermRangeQuery query = new TermRangeQuery(
    "date",
    new BytesRef("20240101"),
    new BytesRef("20241231"),
    true,   // includeLower
    true    // includeUpper
);
For numeric fields indexed with IntField, LongField, FloatField, or DoubleField, use the static range methods on the corresponding point class. These are backed by a BKD tree and are significantly faster than TermRangeQuery for numeric data.
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.FloatField;
import org.apache.lucene.document.DoubleField;
import org.apache.lucene.search.Query;

// Integer range: price between 10 and 100 (inclusive)
Query intRange = IntField.newRangeQuery("price", 10, 100);

// Long range: timestamps
Query longRange = LongField.newRangeQuery("timestamp",
    1_700_000_000L, 1_800_000_000L);

// Float range
Query floatRange = FloatField.newRangeQuery("rating", 3.5f, 5.0f);

// Double range
Query doubleRange = DoubleField.newRangeQuery("score", 0.8, 1.0);
Matches terms that conform to a regular expression using Lucene’s automaton-based regexp engine (not Java’s java.util.regex).
import org.apache.lucene.search.RegexpQuery;
import org.apache.lucene.index.Term;

// Matches "colour" and "color"
RegexpQuery query = new RegexpQuery(new Term("body", "colou?r"));
Lucene’s regexp syntax supports ., *, +, ?, |, [...], and {n,m} repetition but does not support lookaheads or backreferences.
MatchAllDocsQuery matches every document in the index. MatchNoDocsQuery matches none.
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.MatchNoDocsQuery;

// Returns all documents (useful as a filter base)
Query all = new MatchAllDocsQuery();

// Returns no documents
Query none = new MatchNoDocsQuery();
Wraps another query and assigns a constant score to all matching documents, bypassing BM25 scoring. Useful when you need a filter that contributes to ranking but with a fixed weight.
import org.apache.lucene.search.ConstantScoreQuery;

Query filter = new TermQuery(new Term("status", "active"));
ConstantScoreQuery query = new ConstantScoreQuery(filter);
// All matching documents receive a score of 1.0
To assign a specific boost value, wrap with BoostQuery:
import org.apache.lucene.search.BoostQuery;

Query boosted = new BoostQuery(new ConstantScoreQuery(filter), 2.5f);
Returns documents matching any of the sub-queries, but scores each document using only the highest-scoring sub-query match rather than summing scores. A small tieBreakMultiplier is added to distinguish documents that match more than one sub-query.
import org.apache.lucene.search.DisjunctionMaxQuery;
import java.util.List;

Query titleMatch = new TermQuery(new Term("title", "lucene"));
Query bodyMatch  = new TermQuery(new Term("body",  "lucene"));

DisjunctionMaxQuery query = new DisjunctionMaxQuery(
    List.of(titleMatch, bodyMatch),
    0.1f  // tieBreakMultiplier
);

Quick reference table

Query classTypical use case
TermQueryExact keyword match
BooleanQueryCombine multiple queries
PhraseQueryOrdered phrase matching with optional slop
MultiPhraseQueryPhrase matching with synonym alternatives
FuzzyQueryTypo-tolerant term matching
WildcardQueryGlob-style pattern matching
PrefixQueryPrefix / autocomplete
TermRangeQueryLexicographic range on string fields
IntField.newRangeQuery etc.Numeric range on point-indexed fields
RegexpQueryRegular expression on term dictionary
MatchAllDocsQueryReturn all documents
ConstantScoreQueryFilter without scoring
DisjunctionMaxQueryMulti-field best-match scoring
KnnFloatVectorQueryDense vector / semantic search

Build docs developers (and LLMs) love