Query parsers

This section documents the current Solr line (10.0; 9.10.x the maintained 9.x branch), written and verified against the Apache Solr Reference Guide. No specific patch version is pinned. Some capabilities (the Solr Operator on Kubernetes, the package-manager ecosystem, Learning To Rank model training, and expert plugin development) 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.

This section’s bibliography lists the reference material consulted while preparing these pages.

A query parser turns the q parameter (and, for some parsers, other request parameters) into the Lucene query actually executed. Which parser runs is chosen by defType — lucene (the standard parser) unless a request handler’s config says otherwise — and any individual clause can switch parsers inline with local params. This page covers the standard parser’s syntax, DisMax/eDisMax and their many tuning knobs, local params and parameter dereferencing, and a tour of the specialised parsers Solr ships for ranges over functions, joins, nested documents, vector search and more. For the request parameters every parser shares (q, fq, fl, sort, start/rows) see Query basics & parameters; for the function syntax several of these parsers embed, see Function queries.

The standard (Lucene) query parser

The standard (or Lucene) query parser reads q as the classic Lucene query-string grammar: field:value terms, boolean operators (AND, OR, NOT, or the prefix +/-), grouping with parentheses, phrases in double quotes, range syntax ([10 TO 20] inclusive, {10 TO 20} exclusive), wildcards (sol?, sol*), fuzzy matching (solr~2), proximity ("solr apache"~5), and term boosting (solr^3). It is the default parser (defType=lucene) and the fastest of the three general- purpose parsers, but a syntax error anywhere in q fails the whole request, so it suits queries built by your own application rather than raw end-user input. See Standard Query Parser.

curl "http://localhost:8983/solr/techproducts/select" \
  --data-urlencode 'q=name:solr AND (cat:electronics OR cat:memory) AND price:[10 TO 100]' \
  --data-urlencode 'fl=id,name,price,score' \
  --data-urlencode 'wt=json'
# https://solr.apache.org/guide/solr/latest/query-guide/standard-query-parser.html

Two request parameters shape how bare terms are interpreted: df overrides which field an unqualified term (solr instead of name:solr) searches, and q.op overrides the default boolean operator between clauses (OR unless the schema or config says otherwise).

curl "http://localhost:8983/solr/techproducts/select" \
  --data-urlencode 'q=solr apache' \
  --data-urlencode 'df=name' \
  --data-urlencode 'q.op=AND'

DisMax and eDisMax

The standard parser rewards knowing the exact field a term lives in. DisMax and its superset eDisMax (Extended DisMax) instead search several weighted fields at once and are forgiving of the kind of free text a search box actually receives — a stray AND or unbalanced quote in eDisMax degrades gracefully instead of erroring. Both are selected with defType=dismax / defType=edismax; eDisMax is the one to reach for in new work, since it is a strict superset of DisMax’s parameters. See DisMax Query Parser and eDisMax Query Parser.

curl "http://localhost:8983/solr/techproducts/select" \
  --data-urlencode 'defType=edismax' \
  --data-urlencode 'q=solr memory' \
  --data-urlencode 'qf=name^2 manu features' \
  --data-urlencode 'pf=name^4' \
  --data-urlencode 'mm=2<-25%' \
  --data-urlencode 'tie=0.1' \
  --data-urlencode 'wt=json'
Parameter Meaning

qf

Query fields — the fields q’s terms are searched against, with optional per-field boosts (`name^2 manu features).

pf

Phrase fields — fields where the whole q string, taken as a phrase, adds a boost when it matches; the terms still also run through qf.

pf2 / pf3

Like pf, but built from the input’s bigrams / trigrams rather than the whole string — boosts documents where any two (or three) adjacent query terms appear as a phrase, not only the full sequence. eDisMax only.

ps

Default phrase slop applied to pf; ps2 / ps3 override it specifically for pf2 / pf3 (falling back to ps when unset). eDisMax only.

qs

Slop applied to explicit phrase queries the user typed in quotes within q itself.

tie

Tie breaker for combining a term’s per-field scores (0.0 to 1.0): 0.0 (the default) takes only the single best-scoring field; 1.0 sums every field like a plain OR of independent queries. A small value like 0.1 is the common middle ground.

bq

Boost query — one or more additional query clauses added to the score without being required to match, e.g. bq=cat:electronics^1.5.

bf

Boost function(s) — function query results added to the score, e.g. bf=recip(ms(NOW,last_modified),3.16e-11,1,1).

mm

Minimum should match — how many of the (non-mandatory) qf clauses must match; accepts an integer, a percentage, or a conditional spec like 2←25% ("if more than 2 clauses, at most 25% may be missing"). eDisMax defaults mm to 100% once q.op=AND (or an explicit AND) appears anywhere in the query, and to 0% otherwise; mm.autoRelax (eDisMax only) relaxes per-field mm automatically when stop-word removal makes field term counts diverge.

eDisMax adds a boost parameter alongside bf/bq: instead of an additive score contribution, every function listed in boost multiplies the score, which composes more predictably than another bf term when several boosts are stacked.

Field aliasing and user fields

eDisMax lets a field alias stand in for several real fields: f.<alias>.qf=<fields> (and the equivalent for pf) makes <alias>:value in q expand to a search across <fields>, which is handy for exposing a friendly name like text over several concrete columns without a copy field. uf (user fields) is the allow/deny list of field names an end user is permitted to search explicitly inside q (title:foo) — it defaults to uf=* -query (every field except the raw sub-query escape hatch); set it to something narrower, or to uf=-*, when q comes from untrusted input and fielded search should be disabled entirely.

curl "http://localhost:8983/solr/techproducts/select" \
  --data-urlencode 'defType=edismax' \
  --data-urlencode 'q=body:solr' \
  --data-urlencode 'qf=name features' \
  --data-urlencode 'f.body.qf=name features includes' \
  --data-urlencode 'uf=name manu cat body' \
  --data-urlencode 'wt=json'

Local params and parameter dereferencing

Local params attach a small set of key-value pairs to one query clause, most often to switch that clause to a different parser than the request’s overall defType. The syntax is \{!key=value …​} immediately followed by the clause’s value, wrapping curly braces required; a value with no key name is taken as the type local param, so \{!dismax} is shorthand for \{!type=dismax}. An explicit v key gives the clause’s value inline instead of appending it after the closing brace, which is what makes local params composable inside fq, bq, and other multi- valued parameters. See Local Parameters in Queries.

# Two equivalent ways to run one clause through the dismax parser against a chosen field.
curl "http://localhost:8983/solr/techproducts/select" \
  --data-urlencode 'q={!dismax qf=name}solr rocks' \
  --data-urlencode 'wt=json'

curl "http://localhost:8983/solr/techproducts/select" \
  --data-urlencode 'q={!type=dismax qf=name v='"'"'solr rocks'"'"'}' \
  --data-urlencode 'wt=json'

Parameter dereferencing — a local param value prefixed with $ — reads its value from another request parameter instead of embedding it literally, which decouples query text (which may contain spaces or braces of its own) from the surrounding param string and lets the same named parameter be reused from several places in one request:

curl "http://localhost:8983/solr/techproducts/select" \
  --data-urlencode 'q={!type=dismax qf=$myQf v=$qq}' \
  --data-urlencode 'myQf=name manu features' \
  --data-urlencode 'qq=solr memory' \
  --data-urlencode 'wt=json'

Local params are also how fq filters get tagged for faceting exclusion (\{!tag=t}) and how several of the specialised parsers below are invoked — every \{!…​} form in the rest of this page is a local params block.

Specialised parsers

Beyond the general-purpose parsers above, Solr ships a set of narrowly-scoped parsers, each invoked via its own \{!name …​} local params, for jobs the standard/DisMax parsers cannot express. See Other Parsers for the full list; this section covers the ones used most often.

frange and func: filtering and scoring by function

\{!frange} turns a function query into a range filter, keeping only documents whose function value falls within l (lower bound) / u (upper bound), with incl / incu (both default true) controlling whether each bound is inclusive. \{!func} instead runs the function purely as the query value/score, without the surrounding function-query braces val requires. Both are the idiomatic way to filter or sort on a computed value — distance, a boosted combination of fields, age of a document — rather than a stored one.

# Keep only documents whose computed "popularity" function falls in [10, 100].
curl "http://localhost:8983/solr/techproducts/select" \
  --data-urlencode 'q=*:*' \
  --data-urlencode 'fq={!frange l=10 u=100}product(popularity,10)' \
  --data-urlencode 'wt=json'

term and terms: exact-value queries from an external list

\{!term f=<field>}<value> builds a single exact-term query without running <value> through the field’s analyzer — the counterpart to a term filter in other search engines, and the idiom for turning one facet value straight into a filter query. \{!terms f=<field>} takes the same idea for a list, matching any document whose field equals one of several comma-separated (or separator- delimited) values, with a method local param (termsFilter, booleanQuery, automaton, docValuesTermsFilter, …​) to pick the underlying implementation for very large lists.

curl "http://localhost:8983/solr/techproducts/select" \
  --data-urlencode 'q=*:*' \
  --data-urlencode 'fq={!term f=cat}electronics' \
  --data-urlencode 'fq={!terms f=manu_id_s separator=,}apple,belkin,corsair' \
  --data-urlencode 'wt=json'

join and block-join: relating documents without denormalizing

Solr has no native SQL-style join across collections, but two parsers cover the common cases without denormalizing data into a single flat document. \{!join from=<field> to=<field>} matches documents whose to field equals the from field of any document matched by the subordinate query — an "IN (subquery)" over two independently-indexed sets of documents, optionally against another core or collection via fromIndex, with method (index, dvWithScore, topLevelDV, or crossCollection) choosing the join strategy for cardinality and scoring needs. See Join Query Parser.

# Manufacturers with an id referenced by any product matching "ipod" in its title.
curl "http://localhost:8983/solr/techproducts/select" \
  --data-urlencode 'q={!join from=manu_id_s to=id}title:ipod' \
  --data-urlencode 'wt=json'

Block-join is the alternative for documents that are genuinely parent/child (a product and its variants, an invoice and its line items) indexed together as one nested block via nested/child documents. \{!parent which=<parentFilter>} takes a query matched against children and returns their parents; \{!child of=<parentFilter>} runs the other direction, returning children of matched parents. Both accept filters to apply additional fq-style filters only within the block-join evaluation, and \{!parent} accepts score (none/avg/max/min/total) to aggregate child scores onto the parent. See Block Join Query Parser.

# Parent products that have a red variant in stock.
curl "http://localhost:8983/solr/techproducts/select" \
  --data-urlencode 'q={!parent which="content_type:product"}color_s:red AND inStock_b:true' \
  --data-urlencode 'wt=json'

# The reverse: variants belonging to a parent in the "electronics" category.
curl "http://localhost:8983/solr/techproducts/select" \
  --data-urlencode 'q={!child of="content_type:product"}cat:electronics' \
  --data-urlencode 'wt=json'

collapse: performant field collapsing

\{!collapse field=<field>} groups the result set by field, keeping one representative document per group — the same outcome as field collapsing/grouping, but implemented as a post- filter that composes with faceting and is generally the faster choice for a single collapse field. It takes min / max (a function or field deciding which group member survives) and sort (an explicit sort for the representative).

# One document per manufacturer, keeping the highest-priced item from each.
curl "http://localhost:8983/solr/techproducts/select" \
  --data-urlencode 'q=*:*' \
  --data-urlencode 'fq={!collapse field=manu_id_s max=price}' \
  --data-urlencode 'wt=json'

\{!knn f=<denseVectorField> topK=<k>}[v1,v2,…​] finds the topK documents whose stored dense vector is closest to the query vector, using the field’s configured similarity function (cosine/dot-product/Euclidean). Because it wraps a vector search rather than a term lookup, it is typically combined with a filter (fq) or with \{!knn …​} inside a bq/boost clause rather than run alone. Full coverage, including indexing dense-vector fields, is in Dense vector search.

curl "http://localhost:8983/solr/techproducts/select" \
  --data-urlencode 'q={!knn f=embedding topK=10}[0.12,0.98,...,0.44]' \
  --data-urlencode 'wt=json'

Other utility parsers: prefix, boost, switch, surround, min_hash

A handful of narrower parsers round out the set:

Parser Purpose

\{!prefix f=<field>}<value>

An unanalyzed prefix match against <field> — the query-parser equivalent of a leading-edge wildcard, without running <value> through the field’s analyzer.

\{!boost b=<function>}<query>

Wraps <query> and multiplies each matching document’s score by the b function query — only documents <query> matches are scored, unlike bf/boost on eDisMax which add candidates.

\{!switch case.<key>=<query> default=<key>}<key>

Picks one of several case.* queries by matching the clause’s value against the case keys, falling back to default — a server-side "case/switch" over which query actually runs.

\{!surround}

The Surround query language: span/proximity operators (w for ordered, n for unordered proximity, e.g. apache w/3 solr) with finer positional control than phrase-query slop.

\{!min_hash field=<field> sim=<threshold>}<text>

Jaccard-similarity ("near duplicate") matching against a MinHash-encoded field, returning documents whose MinHash signature overlaps <text>’s by at least `sim.

See Other Parsers for the complete parameter reference of each, including the less common \{!field} and \{!complexphrase} parsers.

Where to go next

  • Query basics & parameters — the q/fq/fl/ sort/paging parameters every parser shares.

  • Function queries — the function syntax frange, func, boost, bf and sort-by-function all build on.

  • JSON Request API — expressing query/filter/params (including local params) as a JSON body instead of URL-encoded parameters.

  • Relevance & scoring — how DisMax/eDisMax’s boosts and tie actually shape the final score.

  • Grouping & collapse — the general grouping feature \{!collapse} is a faster alternative to for a single field.