--- title: Highlighting description: Generate snippets for portions of the source text that match the query string canonical: https://docs.paradedb.com/documentation/full-text/highlight --- Highlighting is an expensive process and can slow down query times. We recommend passing a `LIMIT` to any query where `pdb.snippet` or `pdb.snippets` is called to restrict the number of snippets that need to be generated. Highlighting is not supported for fuzzy search. Highlighting refers to the practice of visually emphasizing the portions of a document that match a user's search query. ## Basic Usage `pdb.snippet()` can be added to any query where an `@@@` operator is present. `pdb.snippet` returns the single best snippet, sorted by relevance score. The following query generates highlighted snippets against the `description` field. ```sql SQL SELECT id, pdb.snippet(description) FROM mock_items WHERE description ||| 'shoes' LIMIT 5; ``` ```python Django from paradedb import Match, ParadeDB, Snippet MockItem.objects.filter( description=ParadeDB(Match('shoes', operator='OR')) ).annotate( snippet=Snippet('description') ).values('id', 'snippet')[:5] ``` ```ruby Rails MockItem.search(:description) .matching_any("shoes") .with_snippet(:description) .select(:id) .limit(5) ``` The leading indicator around the highlighted region. The trailing indicator around the highlighted region. Max number of characters for a highlighted snippet. A snippet may contain multiple matches if they are close to each other. By default, `` encloses the snippet. This can be configured with `start_tag` and `end_tag`: ```sql SQL SELECT id, pdb.snippet(description, start_tag => '', end_tag => '') FROM mock_items WHERE description ||| 'shoes' LIMIT 5; ``` ```python Django from paradedb import Match, ParadeDB, Snippet MockItem.objects.filter( description=ParadeDB(Match('shoes', operator='OR')) ).annotate( snippet=Snippet('description', start_sel='', stop_sel='') ).values('id', 'snippet')[:5] ``` ```ruby Rails MockItem.search(:description) .matching_any("shoes") .with_snippet(:description, start_tag: "", end_tag: "") .select(:id) .limit(5) ``` ## Multiple Snippets `pdb.snippets()` returns an array of snippets, allowing you to retrieve multiple highlighted matches from a document. This is particularly useful when a document has several relevant matches spread throughout its content. ```sql SQL SELECT id, pdb.snippets(description, max_num_chars => 15) FROM mock_items WHERE description ||| 'artistic vase' LIMIT 5; ``` ```python Django from paradedb import Match, ParadeDB, Snippets MockItem.objects.filter( description=ParadeDB(Match('artistic vase', operator='OR')) ).annotate( snippets=Snippets('description', max_num_chars=15) ).values('id', 'snippets')[:5] ``` ```ruby Rails MockItem.search(:description) .matching_any("artistic vase") .with_snippets(:description, max_chars: 15) .select(:id) .limit(5) ``` ```ini Expected Response id | snippets ----+----------------------------------------- 19 | {Artistic,"ceramic vase"} (1 row) ``` The leading indicator around the highlighted region. The trailing indicator around the highlighted region. Max number of characters for a highlighted snippet. When `max_num_chars` is small, multiple snippets may be generated for a single document. The maximum number of snippets to return per document. The number of snippets to skip before returning results. Use with `limit` for pagination. The order in which to sort the snippets. Can be `'score'` (default, sorts by relevance) or `'position'` (sorts by appearance in the document). ### Limiting and Offsetting Snippets You can control the number and order of snippets returned using the `limit`, `offset`, and `sort_by` parameters. For example, to get only the first snippet: ```sql SQL SELECT id, pdb.snippets(description, max_num_chars => 15, "limit" => 1) FROM mock_items WHERE description ||| 'running' LIMIT 5; ``` ```python Django from paradedb import Match, ParadeDB, Snippets MockItem.objects.filter( description=ParadeDB(Match('running', operator='OR')) ).annotate( snippets=Snippets('description', max_num_chars=15, limit=1) ).values('id', 'snippets')[:5] ``` ```ruby Rails MockItem.search(:description) .matching_any("running") .with_snippets(:description, max_chars: 15, limit: 1) .select(:id) .limit(5) ``` To get the second snippet (by skipping the first one): ```sql SQL SELECT id, pdb.snippets(description, max_num_chars => 15, "limit" => 1, "offset" => 1) FROM mock_items WHERE description ||| 'running' LIMIT 5; ``` ```python Django from paradedb import Match, ParadeDB, Snippets MockItem.objects.filter( description=ParadeDB(Match('running', operator='OR')) ).annotate( snippets=Snippets('description', max_num_chars=15, limit=1, offset=1) ).values('id', 'snippets')[:5] ``` ```ruby Rails MockItem.search(:description) .matching_any("running") .with_snippets(:description, max_chars: 15, limit: 1, offset: 1) .select(:id) .limit(5) ``` ### Sorting Snippets Snippets can be sorted either by their relevance score (`'score'`) or their position within the document (`'position'`). To sort snippets by their appearance in the document: ```sql SQL SELECT id, pdb.snippets(description, max_num_chars => 15, sort_by => 'position') FROM mock_items WHERE description ||| 'artistic vase' LIMIT 5; ``` ```python Django from paradedb import Match, ParadeDB, Snippets MockItem.objects.filter( description=ParadeDB(Match('artistic vase', operator='OR')) ).annotate( snippets=Snippets('description', max_num_chars=15, sort_by='position') ).values('id', 'snippets')[:5] ``` ```ruby Rails MockItem.search(:description) .matching_any("artistic vase") .with_snippets(:description, max_chars: 15, sort_by: :position) .select(:id) .limit(5) ``` ## Byte Offsets `pdb.snippet_positions()` returns the byte offsets in the original text where the snippets would appear. It returns a two-dimensional integer array where each nested pair is `[start, end)`: the first value is the byte index of the first highlighted byte, and the second value is the byte index immediately after the last highlighted byte. ```sql SQL SELECT id, pdb.snippet(description), pdb.snippet_positions(description) FROM mock_items WHERE description ||| 'shoes' LIMIT 5; ``` ```python Django from paradedb import Match, ParadeDB, Snippet, SnippetPositions MockItem.objects.filter( description=ParadeDB(Match('shoes', operator='OR')) ).annotate( snippet=Snippet('description'), snippet_positions=SnippetPositions('description') ).values('id', 'snippet', 'snippet_positions')[:5] ``` ```ruby Rails MockItem.search(:description) .matching_any("shoes") .with_snippet(:description) .with_snippet_positions(:description) .select(:id) .limit(5) ``` ```ini Expected Response id | snippet | snippet_positions ----+----------------------------+------------------- 4 | White jogging shoes | {{14,19}} 3 | Sleek running shoes | {{14,19}} 5 | Generic shoes | {{8,13}} (3 rows) ```