Search code examples
pythondjangoelasticsearchdjango-haystack

Highlight exact phrase with haystack/elasticsearch in Django


My web app uses Django Haystack with Elasticsearch as the search engine.

My SearchForm child class filters for exact search (content__exact parameter) if the search query contains a token with quotes.

class NepSearchForm(SearchForm):

# ...

    def search(self):
        if not self.is_valid():
            return self.no_query_found()

        if not self.cleaned_data.get('q'):
            return self.no_query_found()

        sqs = self._parse_query(self.cleaned_data['q'])

        if self.load_all:
            sqs = sqs.load_all()

        return sqs

    def no_query_found(self):
        return self.searchqueryset.all()

    def _parse_query(self, query):
        """
        Parse query treating modifiers 'AND', 'OR', 'NOT' to make what they're
        supposed to.
        :param query: query entered in search input box in form
        :param sqs: SearchQuerySet until now
        :return: SearchQuerySet object
        """
        words = iter(shlex.split(query))
        result = self.searchqueryset

        for word in words:
            try:
                if word == 'AND':
                    result = result.filter_and(content=words.__next__())
                elif word == 'OR':
                    # TODO: fail when changing order of the words. See
                    # TODO: functional test:
                    # TODO: test_search_with_OR_modifier_returns_correct_objects
                    result = result.filter_or(content=words.__next__())
                elif word == 'NOT':
                    result = result.exclude(content=words.__next__())
                # if "word" is compounded of more than one non blank word the
                # term is inside quotes
                elif len(word.split()) > 1:
                    result = result.filter(content__exact=word)
                else:
                    result = result.filter(content=word)
            except StopIteration:
                return result

        return result

I'm using the Django template tag {% highlight %} to highlight the terms searched in my app, like in:

{% highlight result.object.<field> with query %}

What I'm seeing is that, when I make a search with quotes with more than one word, separated by spaces, e.g "História de fratura", the search results appears with only the token "de" highlighted. So it seems that Highlighter class does not treat terms with quotes as single tokens to mark them highlighted in search results.

What can I do to highlight the query with a whole term inside quotes in search results?


Solution

  • You can build your own highlighter class as documentation states if default highlighter implementation doesn't work for you.