Browse files

Merge pull request #36 from rlskoeser/per-item-highlighting

per-item highlights on individual result items (with docs & tests)
  • Loading branch information...
Toby White
Toby White committed Jan 1, 2012
2 parents c1c0dc4 + 92e530c commit b399e54de2ff654efa01bce36dc7b7b782aceec6
Showing with 73 additions and 2 deletions.
  1. +25 −1 docs/queryingsolr.rst
  2. +13 −0 sunburnt/
  3. +35 −1 sunburnt/
@@ -763,7 +763,31 @@ The results are shown as a dictionary of dictionaries. The top-level key is the
mapping field names to fragments of highlighted text. In this case we only asked for
highlighting on the ``name`` field. Multiple fragments might be returned for each field,
though in this case we only get one fragment each. The text is highlighted with HTML, and
-the fragments should be suitable for dropping straight into a search template.
+the fragments should be suitable for dropping straight into a search
+If you are using the default result format (that is, if you are not
+specifying a ``constructor`` option when you call
+:meth:``), highlighting results for
+a single result can be accessed on the individual result item as a
+dictionary in a ``solr_highlights`` field. For example, with the
+highlighted query above, you could access highlight snippets for the
+``name`` field on an individual result as
+``result['solr_highlights']['name']``. This is particularly
+convenient for displaying highlighted text snippets in a template;
+e.g., displaying highlights in a Django template might look like this:
+ {% for snippet in %}
+ <p>... {{ snippet|safe }} ...</p>
+ {% endfor %}
+.. Note::
+ The ``solr_highlights`` field will only be available on a result
+ item if highlights were found for that record.
Again, Solr supports a large number of options to the highlighting command,
and all of these are exposed through sunburnt. The full list of supported options is:
@@ -469,6 +469,19 @@ def options(self):
def transform_result(self, result, constructor):
if constructor is not dict: = [constructor(**d) for d in]
+ # in future, highlighting chould be made available to
+ # custom constructors; perhaps document additional
+ # arguments result constructors are required to support, or check for
+ # an optional set_highlighting method
+ else:
+ if result.highlighting:
+ for d in
+ # if the unique key for a result doc is present in highlighting,
+ # add the highlighting for that document into the result dict
+ # (but don't override any existing content)
+ if 'solr_highlights' not in d and \
+ d[self.schema.unique_key] in result.highlighting:
+ d['solr_highlights'] = result.highlighting[d[self.schema.unique_key]]
return result
def params(self):
@@ -11,9 +11,10 @@
from lxml.etree import tostring
import mx.DateTime
-from .schema import SolrSchema, SolrError
+from .schema import SolrSchema, SolrError, SolrResponse
from .search import SolrSearch, MltSolrSearch, PaginateOptions, SortOptions, FieldLimitOptions, FacetOptions, HighlightOptions, MoreLikeThisOptions, params_from_dict
from .strings import RawString
+from .test_sunburnt import MockResponse
from import assert_equal
@@ -541,3 +542,36 @@ def check_mlt_query_options(fields, query_fields, kwargs, output):
def test_mlt_query_options():
for (fields, query_fields, kwargs, output) in mlt_query_options_data:
yield check_mlt_query_options, fields, query_fields, kwargs, output
+# test constructor to text transform result
+class TransformConstructor(object):
+ def __init__(self, **data):
+ = data
+ def __eq__(self, other):
+ # custom equality check to simplify test comparison
+ return ==
+transform_results_data = (
+ # highlighting, constructor, result, first transformed result
+ ({}, dict, SolrResponse(interface.schema, MockResponse(0, 1).xml_response()),
+ {'int_field': 0, 'string_field': 'zero'}),
+ ({0: {'text': 'snippet'}},
+ dict, SolrResponse(interface.schema, MockResponse(0, 1).xml_response()),
+ {'int_field': 0, 'string_field': 'zero', 'solr_highlights': {'text': 'snippet'}}),
+ # highlighting with custom constructor - currently, highlighting is not passed
+ ({0: {'text': 'snippet'}},
+ TransformConstructor, SolrResponse(interface.schema, MockResponse(0, 1).xml_response()),
+ TransformConstructor(int_field=0, string_field='zero')),
+def check_transform_results(highlighting, constructor, result, transformed):
+ q = SolrSearch(interface)
+ result.highlighting = highlighting
+ trans = q.transform_result(result, constructor)
+ assert_equal(trans[0], transformed)
+def test_transform_result():
+ for highlighting, constructor, result, transformed in transform_results_data:
+ yield check_transform_results, highlighting, constructor, result, transformed

0 comments on commit b399e54

Please sign in to comment.