Kosha docs
Documentation menu

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.

POST /v1/namespaces/{namespace}/search
{
  "query_text": "breach notification",
  "highlight": {
    "field": "body",
    "pre_tags": ["<mark>"],
    "post_tags": ["</mark>"]
  }
}
response
{
  "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 wildcard and match_phrase, this one is honoured — only fields with this exact name are highlighted, and only if they are typed Text.
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.