Searching

On models with ZomboDBIndex, use methods from SearchQuerySet/SearchQuerySetMixin to perform various kinds of Elasticsearch queries:

Validation

If you’re receiving queries from the end-user, particularly query string queries, you should call the search methods with validate=True. This will perform Elasticsearch-side validation through the Validate API. When doing that, InvalidElasticsearchQuery may be raised.

from django_zombodb.exceptions import InvalidElasticsearchQuery

queryset = Restaurant.objects.all()
try:
    queryset = queryset.query_string_search("AND steak*", validate=True)
except InvalidElasticsearchQuery:
    messages.error(request, "Invalid search query. Not filtering by search.")

Sorting by score

By default, the resulting queryset from the search methods is unordered. You can get results ordered by Elasticsearch’s score passing sort=True.

Restaurant.objects.query_string_search("brasil~ AND steak*", sort=True)

Alternatively, if you want to combine with your own order_by, you can use the method annotate_score():

Restaurant.objects.query_string_search(
    "brazil* AND steak*"
).annotate_score(
    attr='zombodb_score'
).order_by('-zombodb_score', 'name', 'pk')

Limiting

It’s a good practice to set a hard limit to the number of search results. For most search use cases, you shouldn’t need more than a certain number of results, either because users will only consume some of the high scoring results, or because documents with lower scores aren’t relevant to your process. To limit the results, use the limit parameter on search methods:

Restaurant.objects.query_string_search("brasil~ AND steak*", limit=1000)

Lazy and Chainable

The search methods are like the traditional filter method: they return a regular Django QuerySet that supports all operations, and that’s lazy and chainable. Therefore, you can do things like:

Restaurant.objects.filter(
    name__startswith='Pizza'
).query_string_search(
    'name:Hut'
).filter(
    street__contains='Road'
)

Warning

It’s fine to call filter/exclude/etc. before and after search. If possible, the best would be using only a Elasticsearch query. However, it’s definitely slow to call search methods multiple times on the same queryset! Please avoid this:

Restaurant.objects.query_string_search(
    'name:Pizza'
).query_string_search(
    'name:Hut'
)

While that may work as expected, it’s extremely inneficient. Instead, use compound queries like “bool”. They’ll be much faster. Note that “bool” queries might be quite confusing to implement. Check tutorials about them, like this one.

Missing features

Currently django-zombodb doesn’t support ZomboDB’s offset and sort functions that work on the Elasticsearch side. Regular SQL LIMIT/OFFSET/ORDER BY works fine, therefore traditional QuerySet operations work, but aren’t as performant as doing the same on ES side.