Highlighting
|
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 search results page rarely shows a stored field verbatim — it shows a short snippet around the
matched terms, with those terms wrapped in a tag the UI can style. Solr’s highlighting component
produces that snippet per document per field, driven entirely by hl.* request parameters layered
on top of an ordinary query. This page covers
the three highlighter implementations, the parameters that control them, per-field overrides,
phrase and multivalued-field behavior, and the index-time offset source each highlighter reads from.
Turning highlighting on
Add hl=true and hl.fl (the fields to highlight) to any query. The response gains a top-level
highlighting section keyed by document id, each holding a list of snippets per requested field.
curl "http://localhost:8983/solr/books/select?q=title:distributed&hl=true&hl.fl=title&hl.snippets=2&hl.fragsize=100"
A response looks like:
{
"highlighting": {
"book-42": {
"title": ["A <em>Distributed</em> Systems Primer", "Building <em>Distributed</em> Databases"]
}
}
}
hl.fl accepts a comma- or space-separated list of fields, or a glob (hl.fl=_txt); it defaults to
the df field if omitted. Only fields the query actually matched against produce snippets unless
hl.requireFieldMatch=false is set, which highlights a field for terms that matched a *different
field (common when a query targets a copyField destination).
Choosing a highlighter
Three highlighter implementations exist, selected with hl.method; each trades off accuracy, speed,
and the index-time data it needs.
hl.method |
When to use |
|---|---|
|
The default since Solr 6.4. A single Lucene component that picks the fastest available offset source automatically (postings, term vectors, or on-the-fly re-analysis), handles nearly every query type including wildcards and complex boolean/phrase queries, and needs no term vectors to work well. Start here and only move off it for a specific gap. |
|
The oldest highlighter ( |
|
|
curl "http://localhost:8983/solr/books/select?q=title:%22distributed+systems%22&hl=true&hl.fl=title&hl.method=unified"
The Unified Highlighter’s own offset-source preference, cheapest to most expensive, is: postings
with storeOffsetsWithPositions (see below), then term vectors, then plain re-analysis — it uses
whichever the field actually has, so upgrading a field’s index-time options can speed it up without
changing any hl.* parameter.
storeOffsetsWithPositions and term-vector offsets
Highlighting needs to know where each matched term sits in the original text, and that data comes
from one of two index-time sources declared on the field (or field type), not from hl.*:
-
storeOffsetsWithPositions="true"on the field, alongsideindexed="true", stores character offsets in the postings list itself. This is what letshl.method=unifieduse its fast postings offset strategy without any term-vector overhead — the recommended setup for the default highlighter on large collections. -
Term vectors —
termVectors="true" termPositions="true" termOffsets="true"— store a separate per-document, per-field list of terms with positions and offsets. The FastVector highlighter requires this; the Unified Highlighter will fall back to it when postings offsets are not available; the Original highlighter needs neither and instead re-tokenizes the stored field value, so that field must also bestored="true".
<!-- schema.xml: recommended for hl.method=unified on a large text field -->
<field name="body" type="text_general" indexed="true" stored="true"
storeOffsetsWithPositions="true"/>
<!-- schema.xml: required for hl.method=fastVector -->
<field name="body_fvh" type="text_general" indexed="true" stored="true"
termVectors="true" termPositions="true" termOffsets="true"/>
Both options enlarge the index on disk; storeOffsetsWithPositions is generally the cheaper of the
two and is why it is favored for the Unified Highlighter. Field configuration is covered in full in
Schema & fields and
Field types.
Core hl.* parameters
| Parameter | Effect |
|---|---|
|
Fields to highlight (comma/space-separated list or glob). |
|
Maximum number of snippets returned per field (default |
|
Target snippet length in characters (default |
|
Tags wrapping each matched term, default |
|
When |
|
Whether wildcard/prefix/fuzzy/range query terms are highlighted, not just
exact term matches. Defaults to |
|
The |
|
How much of a field’s value is scanned when building fragments before
giving up (default |
|
Highlight against a different parsed query than the one that selected the document — for example, to also mark synonyms the main query expanded but the user did not type. |
curl "http://localhost:8983/solr/books/select?q=body:resilient&hl=true&hl.fl=body&hl.snippets=3&hl.fragsize=120&hl.bs.type=SENTENCE&hl.simple.pre=%3Cmark%3E&hl.simple.post=%3C%2Fmark%3E"
The full parameter reference, including the FastVector-only hl.fragListBuilder,
hl.fragmentsBuilder, and hl.boundaryScanner family, is on
Highlighting.
Per-field parameter overrides
Any hl. parameter can be overridden for one field with an f.<field>.hl. prefix, which takes
precedence over the plain hl.* value for that field only. This is the usual way to give a short
title field a single unfragmented snippet while a long body field gets several short ones.
curl "http://localhost:8983/solr/books/select?q=title:distributed+body:resilient&hl=true" \
--data-urlencode "hl.fl=title,body" \
--data-urlencode "f.title.hl.fragsize=0" \
--data-urlencode "f.title.hl.snippets=1" \
--data-urlencode "f.body.hl.fragsize=150" \
--data-urlencode "f.body.hl.snippets=3"
Phrase and multivalued-field highlighting
The Unified and FastVector highlighters both account for term proximity: a snippet containing the
exact phrase a match_phrase-style query asked for is preferred over one where the same terms
appear scattered, and only the terms that actually satisfy the phrase are tagged rather than every
occurrence of each individual word. The Original highlighter, lacking positional awareness by
default, is more prone to highlighting a term outside its matching phrase context.
A multivalued field (an array of strings, one Solr field with several stored values) is highlighted
per value: each entry that contains a match can contribute its own snippet, and hl.snippets limits
how many are returned in total across all the field’s values, not per value. Where a phrase query
must not match across the boundary between two values of the same multivalued field, set a
positionIncrementGap greater than the maximum phrase slop on that field’s type — covered in
Schema & fields — so a match spanning two array entries
cannot be found (or highlighted) as though it were contiguous text.
curl "http://localhost:8983/solr/books/select?q=tags:%22machine+learning%22&hl=true&hl.fl=tags&hl.method=unified"
Related pages
-
Query basics & parameters — the
q,fl, and general request-parameter conventions thathl.*parameters build on. -
Text analysis — how a field’s analyzer determines what counts as a "term" for both matching and highlighting.
-
Schema & fields and Field types — declaring
storeOffsetsWithPositions, term vectors, andpositionIncrementGapon a field. -
Relevance & scoring — how the Unified Highlighter’s passage ranking relates to the query’s own scoring.
-
Spell check & suggest — the companion feature for "did you mean" and autocomplete alongside highlighted results.