Skip to content

Commit

Permalink
Added optional argument to spelling_suggestion that lets you provid…
Browse files Browse the repository at this point in the history
…e a different query than the one built by the SearchQuerySet.

Useful for passing along a raw user-provided query, especially when there is a lot of post-processing done.
  • Loading branch information
toastdriven committed Aug 31, 2009
1 parent 083cb44 commit 167030a
Show file tree
Hide file tree
Showing 10 changed files with 41 additions and 18 deletions.
4 changes: 2 additions & 2 deletions docs/searchbackend_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ Clears the backend of all documents/objects for a collection of models.
This method MUST be implemented by each backend, as it will be highly
specific to each one.

``search(self, query_string, sort_by=None, start_offset=0, end_offset=None, fields='', highlight=False, facets=None, date_facets=None, query_facets=None, narrow_queries=None, **kwargs)``
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
``search(self, query_string, sort_by=None, start_offset=0, end_offset=None, fields='', highlight=False, facets=None, date_facets=None, query_facets=None, narrow_queries=None, spelling_query=None, **kwargs)``
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Takes a query to search on and returns dictionary.

Expand Down
6 changes: 4 additions & 2 deletions docs/searchquery_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@ Backend-Specific Methods

When implementing a new backend, the following methods will need to be created:

``run(self)``
~~~~~~~~~~~~~
``run(self, spelling_query=None)``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Builds and executes the query. Returns a list of search results.

Optionally passes along an alternate query for spelling suggestions.

``build_query(self)``
~~~~~~~~~~~~~~~~~~~~~

Expand Down
13 changes: 11 additions & 2 deletions docs/searchqueryset_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -472,8 +472,8 @@ Example::
# 'queries': {}
# }

``spelling_suggestion(self)``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``spelling_suggestion(self, preferred_query=None)``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Returns the spelling suggestion found by the query.

Expand All @@ -485,10 +485,19 @@ run. Search results will be populated as normal but with an additional spelling
suggestion. Note that this does *NOT* run the revised query, only suggests
improvements.

If provided, the optional argument to this method lets you specify an alternate
query for the spelling suggestion to be run on. This is useful for passing along
a raw user-provided query, especially when there are many methods chained on the
``SearchQuerySet``.

Example::

sqs = SearchQuerySet().auto_query('mor exmples')
sqs.spelling_suggestion() # u'more examples'
# ...or...
suggestion = SearchQuerySet().spelling_suggestion('moar exmples')
suggestion # u'more examples'


.. _field-lookups:
Expand Down
10 changes: 5 additions & 5 deletions haystack/backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def clear(self, models=[]):

def search(self, query_string, sort_by=None, start_offset=0, end_offset=None,
fields='', highlight=False, facets=None, date_facets=None, query_facets=None,
narrow_queries=None, **kwargs):
narrow_queries=None, spelling_query=None, **kwargs):
"""
Takes a query to search on and returns dictionary.
Expand Down Expand Up @@ -247,10 +247,10 @@ def __setstate__(self, obj_dict):

self.backend = loaded_backend.SearchBackend()

def run(self):
def run(self, spelling_query=None):
"""Builds and executes the query. Returns a list of search results."""
final_query = self.build_query()
results = self.backend.search(final_query, highlight=self.highlight)
results = self.backend.search(final_query, highlight=self.highlight, spelling_query=spelling_query)
self._results = results.get('results', [])
self._hit_count = results.get('hits', 0)
self._facet_counts = results.get('facets', {})
Expand Down Expand Up @@ -313,15 +313,15 @@ def get_facet_counts(self):

return self._facet_counts

def get_spelling_suggestion(self):
def get_spelling_suggestion(self, preferred_query=None):
"""
Returns the spelling suggestion received from the backend.
If the query has not been run, this will execute the query and store
the results.
"""
if self._spelling_suggestion is None:
self.run()
self.run(spelling_query=preferred_query)

return self._spelling_suggestion

Expand Down
2 changes: 1 addition & 1 deletion haystack/backends/dummy_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def clear(self, models):

def search(self, query_string, sort_by=None, start_offset=0, end_offset=None,
fields='', highlight=False, facets=None, date_facets=None, query_facets=None,
narrow_queries=None, **kwargs):
narrow_queries=None, spelling_query=None, **kwargs):
if query_string == 'content__exact hello AND content__exact world':
return {
'results': [DummySearchResult('haystack', 'dummymodel', 1, 1.5)],
Expand Down
10 changes: 8 additions & 2 deletions haystack/backends/solr_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def clear(self, models=[], commit=True):

def search(self, query_string, sort_by=None, start_offset=0, end_offset=None,
fields='', highlight=False, facets=None, date_facets=None, query_facets=None,
narrow_queries=None, **kwargs):
narrow_queries=None, spelling_query=None, **kwargs):
if len(query_string) == 0:
return {
'results': [],
Expand Down Expand Up @@ -106,6 +106,9 @@ def search(self, query_string, sort_by=None, start_offset=0, end_offset=None,
kwargs['spellcheck'] = 'true'
kwargs['spellcheck.collate'] = 'true'
kwargs['spellcheck.count'] = 1

if spelling_query:
kwargs['spellcheck.q'] = spelling_query

if facets is not None:
kwargs['facet'] = 'on'
Expand Down Expand Up @@ -339,7 +342,7 @@ def build_query(self):

return final_query

def run(self):
def run(self, spelling_query=None):
"""Builds and executes the query. Returns a list of search results."""
final_query = self.build_query()
kwargs = {
Expand Down Expand Up @@ -375,6 +378,9 @@ def run(self):
if self.narrow_queries:
kwargs['narrow_queries'] = self.narrow_queries

if spelling_query:
kwargs['spelling_query'] = spelling_query

results = self.backend.search(final_query, **kwargs)
self._results = results.get('results', [])
self._hit_count = results.get('hits', 0)
Expand Down
7 changes: 5 additions & 2 deletions haystack/backends/whoosh_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def optimize(self):

def search(self, query_string, sort_by=None, start_offset=0, end_offset=None,
fields='', highlight=False, facets=None, date_facets=None, query_facets=None,
narrow_queries=None, **kwargs):
narrow_queries=None, spelling_query=None, **kwargs):
if not self.setup_complete:
self.setup()

Expand Down Expand Up @@ -279,7 +279,10 @@ def search(self, query_string, sort_by=None, start_offset=0, end_offset=None,
return self._process_results(raw_results, highlight=highlight, query_string=query_string)
else:
if getattr(settings, 'HAYSTACK_INCLUDE_SPELLING', False):
spelling_suggestion = self.create_spelling_suggestion(query_string)
if spelling_query:
spelling_suggestion = self.create_spelling_suggestion(spelling_query)
else:
spelling_suggestion = self.create_spelling_suggestion(query_string)
else:
spelling_suggestion = None

Expand Down
4 changes: 2 additions & 2 deletions haystack/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ def facet_counts(self):
clone = self._clone()
return clone.query.get_facet_counts()

def spelling_suggestion(self):
def spelling_suggestion(self, preferred_query=None):
"""
Returns the spelling suggestion found by the query.
Expand All @@ -406,7 +406,7 @@ def spelling_suggestion(self):
presenting the data.
"""
clone = self._clone()
return clone.query.get_spelling_suggestion()
return clone.query.get_spelling_suggestion(preferred_query)


# Utility methods.
Expand Down
1 change: 1 addition & 0 deletions tests/core/tests/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ def test_spelling(self):
sqs = self.bsqs.filter(content='Indx')
self.assert_(isinstance(sqs, SearchQuerySet))
self.assertEqual(sqs.spelling_suggestion(), None)
self.assertEqual(sqs.spelling_suggestion('indexy'), None)

def test_raw_search(self):
self.assertEqual(len(self.bsqs.raw_search('foo')), 0)
Expand Down
2 changes: 2 additions & 0 deletions tests/solr_tests/tests/solr_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ def test_search(self):

self.assertEqual(self.sb.search('Indx')['hits'], 0)
self.assertEqual(self.sb.search('Indx')['spelling_suggestion'], 'index')
self.assertEqual(self.sb.search('Indx', spelling_query='indexy')['spelling_suggestion'], 'index')

self.assertEqual(self.sb.search('', facets=['name']), {'hits': 0, 'results': []})
results = self.sb.search('Index', facets=['name'])
Expand Down Expand Up @@ -181,6 +182,7 @@ def tearDown(self):
def test_get_spelling(self):
self.sq.add_filter('content', 'Indx')
self.assertEqual(self.sq.get_spelling_suggestion(), u'index')
self.assertEqual(self.sq.get_spelling_suggestion('indexy'), u'index')


class LiveSolrSearchQuerySetTestCase(TestCase):
Expand Down

0 comments on commit 167030a

Please sign in to comment.