Function queries
|
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 function query evaluates a small expression — built from field values, constants, and nested functions — to a numeric value per document, and that value can then become a score, a filter bound, a sortable column, or an extra column in the response. This is Solr’s mechanism for scoring or ranking by something other than text relevance: popularity, price, geographic distance, recency, or any combination the built-in function catalog can express. See Function Queries for the complete reference and function list. Function queries are what relevance & scoring reaches for to blend a custom signal into the score, and they are invoked through the query-parser mechanism covered in query parsers.
Function query syntax: \{!func} and \{!frange}
A function is not valid Lucene query syntax by itself — it has to be wrapped so Solr knows to evaluate it as a function rather than parse it as a field:query clause. Two dedicated query parsers do that:
| Parser | Role |
|---|---|
|
Turns the whole function into a scoring query: every document gets the function’s
value as its |
|
Turns the function into an unscored range filter: only documents whose function
value falls within |
# {!func}: score purely by a recip() decay of price -- cheaper items score higher.
curl --get "http://localhost:8983/solr/books/select" \
--data-urlencode 'q={!func}recip(price,1,1000,1000)' \
--data-urlencode 'fl=id,title,price,score'
# {!frange}: filter to documents whose computed "value density" falls in [1,5],
# combined with a normal text query.
curl --get "http://localhost:8983/solr/books/select" \
--data-urlencode 'q=title:earthsea' \
--data-urlencode 'fq={!frange l=1 u=5}div(popularity,price)'
# https://solr.apache.org/guide/solr/latest/query-guide/function-queries.html
A function can also appear without either parser, as the value of the special val pseudo-field
inside a lucene/edismax query string (val:"recip(price,1,1000,1000)"), or as one of the
boost functions the DisMax/eDisMax parsers accept directly — bf (an additively-combined boost
function, itself effectively \{!func}) and eDisMax’s boost (a multiplicatively-combined one).
Nested calls, field references, and numeric/quoted-string constants are all valid function
arguments, and whitespace inside the argument list is fine as long as the whole expression stays one
unbroken token when it is not quoted.
Returning functions as pseudo-fields
Any function can be listed in fl alongside real field names; Solr evaluates it per hit and adds it
to the response under the literal function text as its key — a pseudo-field, computed but never
stored. This is the way to see a ranking signal’s actual value without adding a stored field for it,
or to hand a client a derived number (a discount, a distance, a normalized score) it would otherwise
have to compute itself.
curl --get "http://localhost:8983/solr/books/select" \
--data-urlencode 'q=*:*' \
--data-urlencode 'fl=id,title,price,score,sum(price,shipping_f),div(popularity,price)'
# each hit gains "sum(price,shipping_f)" and "div(popularity,price)" keys alongside id/title/price/score
# https://solr.apache.org/guide/solr/latest/query-guide/function-queries.html
fl accepts an alias for a function pseudo-field with alias:function(…) syntax
(fl=discount:sum(price,shipping_f)), which is worth using whenever the raw function text would be
an awkward JSON/response key for a client to consume.
Sorting on functions
sort accepts a function exactly where it accepts a field name, each followed by asc/desc — useful whenever the ranking should follow a computed value (distance from a point, a blended
popularity/price score) rather than any single stored field.
# Rank by "value for money" -- popularity per unit price -- highest first.
curl --get "http://localhost:8983/solr/books/select" \
--data-urlencode 'q=*:*' \
--data-urlencode 'sort=div(popularity,price) desc'
# https://solr.apache.org/guide/solr/latest/query-guide/function-queries.html
Sorting on a function is more expensive than sorting on a docValues-backed field because Solr evaluates the expression for every candidate document rather than reading a precomputed column; for a sort that is used constantly, consider computing and storing the value at index time instead if the inputs rarely change.
The function catalog
The full catalog lives at Function Queries; the groups below are the ones reached for most often.
Math functions
sum, sub, product, div, abs, pow, sqrt, log, min, max, map (piecewise
remapping of a value range), and linear(x,m,c) (m*x+c) cover arithmetic on field values and
constants, nested arbitrarily deep — div(sum(a,b),product(c,d)) is a valid single function.
Relevancy functions
-
query(subquery, default)— runs another query as a function, returning its score for a matching document ordefaultfor a non-matching one. This is the standard way to fold a second, independently-scored query into an arithmetic expression alongside non-textual signals, e.g.product(query(\{!edismax v=$qq}),recip(price,1,1000,1000)). -
scale(function,min,max)— linearly rescales a function’s output range across the whole result set into[min,max]. Because it depends on the min/max actually observed for the current query, it needs a second pass over the candidates and is comparatively expensive; use it to bring differently-scaled signals (a raw popularity count and a0..1text score) onto comparable footing before combining them. -
recip(x,m,a,b)— computesa/(m*x+b), a reciprocal decay that is large whenxis small and approaches0asxgrows; the standard shape for "prefer cheap/near/old-less" signals such as price or distance without a hard cutoff.recip(price,1,1000,1000)in the examples above is1000 / (price + 1000). -
norm(field)— exposes the Lucene index-time norm for a field, when norms are enabled.
Distance functions
dist(power,x1,y1,x2,y2,…) computes a Minkowski-family distance (power 2 is Euclidean, 1 is
Manhattan) between two vectors given as function or field arguments; sqedist is the squared
Euclidean variant (cheaper — skips the square root — when only relative ordering matters);
hsin/geodist compute great-circle (haversine) distance between two lat/lon points, the function
form of the same geospatial distance used by the \{!geofilt}/\{!bbox} query parsers on
spatial fields; strdist scores string similarity (edit
distance, Jaro-Winkler, and others) for fuzzy-matching two text values as a number rather than a
match/no-match filter. vectorSimilarity() computes the configured similarity between two dense
vectors and is the scoring primitive behind dense vector
search's kNN query.
Boolean functions
and, or, xor, not combine boolean-valued functions; exists(field) tests whether a field has
a value on the document; gt, gte, lt, lte, eq compare two functions/constants; if(test,
value_if_true, value_if_false) is the general-purpose conditional every one of the above typically
feeds into.
Date functions
ms(date) converts a date field or constant to epoch milliseconds; ms(date1,date2) returns the
difference in milliseconds between two dates — the building block for a recency signal such as
recip(ms(NOW,published_dt),3.16e-11,1,1), which decays smoothly as published_dt recedes from
NOW.
Custom functions: writing a ValueSource
When the catalog above cannot express a signal, Solr’s function-query layer is itself extensible: a
ValueSourceParser plugin, declared in solrconfig.xml and backed by a Java ValueSource
implementation, adds a new named function that behaves exactly like a built-in one everywhere
functions are accepted — \{!func}, fl, sort, bf/boost. Writing one is a genuine Java
plugin (implement ValueSource.getValues() to produce a per-segment FunctionValues), so treat it
as a last resort after checking whether map(), if(), or a query()-wrapped subquery already
covers the case; for a lighter-weight escape hatch, Solr also ships a JavaScript-expression
ValueSource (the Expression function) that lets a short script stand in for a full plugin class.
See Solr Plugins for
how plugin classes (ValueSourceParser among them) are packaged and registered.
Continue with Relevance & scoring for how function
queries combine with text relevance and boosting, or Query
parsers for the func/frange parsers' place among Solr’s other query parsers.