Feature
Highlighting
Ask for a highlight and each hit comes back with a
highlights array: the field's value with the matched query terms
wrapped in tags you choose.
{
"query_text": "breach notification",
"highlight": {
"field": "body",
"pre_tags": ["<mark>"],
"post_tags": ["</mark>"]
}
}
{
"results": [{
"doc_id": "d1",
"score": 2.4079,
"fields": [ … ],
"highlights": [
"Report any <mark>breach</mark> within 72 hours of <mark>notification</mark>."
]
}],
"total_hits": 1,
"total_hits_relation": "eq"
}
Parameters
- field string · required
-
Which field to highlight. Unlike
wildcardandmatch_phrase, this one is honoured — only fields with this exact name are highlighted, and only if they are typedText. - pre_tags string[] · default ["<b>"]
- Opening tag. Only the first element is used.
- post_tags string[] · default ["</b>"]
- Closing tag. Only the first element is used.
The arrays exist for OpenSearch request compatibility, where they rotate across matches to distinguish them. Kosha accepts the array shape and uses element zero.
What you get back
Three properties of the output are worth knowing before you render it:
It is the whole field, not a snippet
highlights contains the complete field value with tags inserted —
there is no fragment extraction, fragment size, or fragment count. For a long
body field that is a lot of text per hit. If you need snippets, cut around the
first tag client-side, or highlight a shorter field.
The first occurrence of each term is tagged
Each query term is tagged once, at its first occurrence in the field. A term appearing five times is marked once. This keeps the response bounded, at the cost of not showing every match.
Matching is by substring, not by token
Tagging is a case-insensitive substring search, so a query for
cat highlights the first three letters of category.
The scoring path is token-based and would not have matched that document on
cat at all — highlighting is looser than retrieval, and only ever
runs on documents that already matched.
Choose distinctive tags
Terms are applied one after another to the string that previous terms already
tagged. A query term that also occurs inside your markup — a bare
b against the default <b> tags — can end up
tagged inside a tag. <mark>, or a sentinel like
[[hl]] that you replace after escaping, avoids the whole class
of problem.
Which terms are highlighted
Highlighting uses the terms from query_text. It does not use
terms produced by a wildcard expansion or a
phrase, so a pattern-only or phrase-only
query returns hits with nothing marked in them. Sending the literal words in
query_text alongside the phrase is the workaround, with the caveat
that a phrase query overrides which terms are scored.
Escaping
Kosha inserts your tags into the stored value verbatim and does no HTML escaping of the surrounding text. If the indexed content can contain markup and you render the result as HTML, escape it on your side — highlight with a non-HTML sentinel, escape the string, then swap the sentinel for real tags.