Highlight Search Results


  • When making a Full-Text Search query,
    in addition to retrieving documents that contain the searched terms in the results,
    you can also request to get a list of text fragments that highlight the searched terms.

  • The highlighted terms can enhance user experience when searching for documents with specific content.

  • This article shows highlighting search results when making a dynamic-query.
    For highlighting search results when querying a static-index see highlight index search results.



Highlight - basic example

# Make a full-text search dynamic query:
# ======================================

# Define a callback that takes highlightings as an argument
sales_highlightings: Optional[Highlightings] = None

def _sales_highlights(highlightings: Highlightings):
    # You may use the results (highlightings) here in any way desired
    sales_highlightings = highlightings

employees_result = list(  # Execute the query inside the parenthesis
    session
    # Make a query on 'Employees' collection
    .query(object_type=Employee)
    # Search for documents containing the term 'sales' in their 'Notes' field
    .search("Notes", "sales")
    # Request to highlight the searched term by calling 'Highlight'
    .highlight(
        "Notes",  # The document-field name in which we search
        35,  # Max length of each text fragment
        4,  # Max number of fragments to return per document
        _sales_highlights,  # An out param for getting the highlighted text fragments
    )
)
from "Employees"
where search(Notes, "sales")
include highlight(Notes, 35, 4)

# Process results:
# ================

# 'employees_results' contains all Employee DOCUMENTS that have 'sales' in their 'Notes' field.
# 'sales_highlights' contains the text FRAGMENTS that highlight the 'sales' term.

builder = ["<ul>", {os.linesep}]
for employee in employees_result:
    # Call 'get_fragments' to get all fragments for the specified employee Id
    fragments = sales_highlightings.get_fragments(employee.Id)
    for fragment in fragments:
        builder.append(f"{os.linesep}<li>Doc: {employee.Id} Fragment: {fragment}</li>")

fragments_html = builder.append(f"{os.linesep}</ul>")

# The resulting fragments_html:
# ============================

# <ul>
#   <li>Doc: employees/2-A Fragment: company as a <b style="background:yellow">sales</b></li>
#   <li>Doc: employees/2-A Fragment: promoted to <b style="background:yellow">sales</b> manager in</li>
#   <li>Doc: employees/2-A Fragment: president of <b style="background:yellow">sales</b> in March 1993</li>
#   <li>Doc: employees/2-A Fragment: member of the <b style="background:yellow">Sales</b> Management</li>
#   <li>Doc: employees/3-A Fragment: hired as a <b style="background:yellow">sales</b> associate in</li>
#   <li>Doc: employees/3-A Fragment: promoted to <b style="background:yellow">sales</b> representativ</li>
#   <li>Doc: employees/5-A Fragment: company as a <b style="background:yellow">sales</b> representativ</li>
#   <li>Doc: employees/5-A Fragment: promoted to <b style="background:yellow">sales</b> manager in</li>
#   <li>Doc: employees/5-A Fragment: <b style="background:yellow">Sales</b> Management." </li>
#   <li>Doc: employees/6-A Fragment: for the <b style="background:yellow">Sales</b> Professional.</li>
#  </ul>

Highlight tags

  • By default, the highlighted term is wrapped with the following html:
    <b style="background:yellow">term</b>

  • When requesting to highlight multiple terms,
    the background color returned for each different term will be in the following order:

    •  yellow,
    •  lawngreen,
    •  aquamarine,
    •  magenta,
    •  palegreen,
    •  coral,
    •  wheat,
    •  khaki,
    •  lime,
    •  deepskyblue,
    •  deeppink,
    •  salmon,
    •  peachpuff,
    •  violet,
    •  mediumpurple,
    •  palegoldenrod,
    •  darkkhaki,
    •  springgreen,
    •  turquoise,
    •  powderblue
  • The html tags that wrap the highlighted terms can be customized to any other tags.
    See customize tags below.

Highlight results in Studio

Figure 1. Fragments results

View highlighted fragments in the Query View

  1. Auto-Index
    This is the auto-index that was created by the server to serve the dynamic-query.

  2. Results tab
    The results tab contains the resulting documents that match the provided RQL query.

  3. Highlight tab
    The highlight tab shows the resulting fragments that were included in the query result.

Highlight - customize tags

  • The html tags that wrap the highlighted terms can be customized to any other tags.

# Define customized tags to use for highlighting the searched terms
# =================================================================
tags_to_use = HighlightingOptions(
    # Provide strings of your choice to 'PreTags' & 'PostTags', e.g.:
    # the first term searched for will be wrapped with '+++'
    # the second term searched for will be wrapped with '<<<' & '>>>'
    pre_tags=["+++", "<<<"],
    post_tags=["+++", ">>>"],
)

# Define a callback that takes highlightings as an argument
manager_highlightings: Optional[Highlightings] = None

def _manager_highlights(highlightings: Highlightings):
    # You may use the results (highlightings) here in any way desired
    manager_highlightings = highlightings

# Make a full-text search dynamic query:
# ======================================
employees_result = list(
    session.query(object_type=Employee)
    # Search for:
    #  * documents containing the term 'sales' in their 'Notes' field
    #  * OR for documents containing the term 'manager' in their 'Title' field
    .search("Notes", "sales")
    .search("Title", "manager")
    # Call 'Highlight' for each field searched
    # Pass 'tagsToUse' to OVERRIDE the default tags used
    .highlight("Notes", 35, 1, _sales_highlights)
    .highlight("Title", 35, 1, tags_to_use, _manager_highlights)
)
from "Employees"
where (search(Notes, "sales") or search(Title, "manager"))
include highlight(Notes, 35, 1, $p0), highlight(Title, 35, 1, $p1)
{
"p0":{"PreTags":["+++","<<<"],"PostTags":["+++",">>>"]},
"p1":{"PreTags":["+++","<<<"],"PostTags":["+++",">>>"]}
}

# The resulting salesHighlights fragments:
# ========================================
#
# "for the +++Sales+++ Professional."
# "hired as a +++sales+++ associate in"
# "company as a +++sales+++"
# "company as a +++sales+++ representative"
#
# The resulting managerHighlights fragments:
# ==========================================
#
# "Sales <<<Manager>>>"

Highlight - projected results

# Make a full-text search dynamic query & project results:
# ========================================================

# Define a callback that takes highlightings as an argument
terms_highlightings: Optional[Highlightings] = None

def _terms_highlights(highlightings: Highlightings):
    # You may use the results (highlightings) here in any way desired
    terms_highlightings = highlightings

employees_projected = list(
    session.query(object_type=Employee)
    .search("Notes", "manager german")
    .highlight("Notes", 35, 2, _terms_highlights)
    .select_fields_query_data(
        QueryData.custom_function("o", "{ Name: o.FirstName + ' ' + o.LastName, Title: o.Title }"),
    )
)

# todo reeb & gracjan: lets implement it after 5.4 release
#  i have a perfect ticket for that
#  https://issues.hibernatingrhinos.com/issue/RDBC-820#focus=Comments-67-1050834.0-0
from "Employees" as x
where search(x.Notes, "manager german")
select { Name : "{0} {1}".format(x.FirstName, x.LastName), Title : x.Title }
include highlight(Notes, 35, 2)

# The resulting fragments from termsHighlights:
# =============================================
#
# "to sales <b style=\"background:yellow\">manager</b> in March"
# "and reads <b style=\"background:lawngreen\">German</b>.  He joined"
# "to sales <b style=\"background:yellow\">manager</b> in January"
# "in French and <b style=\"background:lawngreen\">German</b>."
#
# NOTE: each search term is wrapped with a different color
# 'manager' is wrapped with yellow
# 'german' is wrapped with lawngreen

Syntax

def highlight(
    self,
    field_name: str,
    fragment_length: int,
    fragment_count: int,
    highlightings_callback: Callable[[Highlightings], None],
    options: Optional[HighlightingOptions] = None,
) -> DocumentQuery[_T]: ...
Parameter Type Description
field_name str Name of the field that contains the searched terms to highlight
fragment_length int Maximum length of a text fragment
Must be >= 18
fragment_count int Maximum number of text fragments that will be returned
highlightings_callback Callable[[Highlightings], None] A callback function to retrieve the highlighted text fragments for each returned result
options (Optional) HighlightingOptions Customizing options


Highlighting options:

def __init__(self, group_key: str = None, pre_tags: List[str] = None, post_tags: List[str] = None):
    self.group_key = group_key
    self.pre_tags = pre_tags
    self.post_tags = post_tags
Option Type Description
group_key str Grouping key for the results.
Used when highlighting query results from a Map-Reduce index.
If None results are grouped by document ID (default).
Note: Highlighting is Not available for dynamic aggregation queries.
pre_tags List[str] Array of PRE tags used to wrap the highlighted search terms in the text fragments.
post_tags List[str] Array of POST tags used to wrap the highlighted search terms in the text fragments.


Highlightings object:

def __init__(self, field_name: str):
    self.field_name = field_name
    ...

@property
def result_indents(self) -> Set[str]: ...
Property Type Description
field_name str Name of the field that contains the searched terms to highlight
result_indents Set[str] The resulting keys (document IDs, or the map-reduce keys)

def get_fragments(self, key: str) -> List[str]: ...
Method Return Type Description
get_fragments List[str] Returns the list of the highlighted text fragments for the passed document ID, or the map-reduce key