Search that runs a database LIKE over a text column works until it does not. It is slow once the table is large, and it has no idea which result is more relevant than another. Elasticsearch is built for exactly this job, and Django integrates with it cleanly.
Why not just the database
A wildcard text match cannot use a normal index, so it scans. It also treats every match as equal: a term in the title ranks the same as a term buried in a description. Real search needs tokenizing, ranking, and tolerance for typos, and that is a search engine, not a column.
A search engine starts from a different structure, an inverted index: a map from each term to the documents that contain it. Text is split into terms when it is written, so a query looks terms up instead of scanning rows, and scoring can weigh where and how often each term appears. That one structure is why the rest of this post works the way it does: the index is built from the database, it has to be kept in sync, and relevance is something you tune.
Define a document
With django-elasticsearch-dsl, a document declares which model fields get indexed and how.
from django_elasticsearch_dsl import Document, fields
from django_elasticsearch_dsl.registries import registry
from products.models import Product
@registry.register_document
class ProductDocument(Document):
vendor = fields.TextField(attr="vendor.name")
class Index:
name = "products"
class Django:
model = Product
fields = ["name", "sku", "description"]
Keep the index in sync
The library hooks model save and delete to update the index automatically. The gap is bulk operations: a bulk_update does not fire those hooks, so anything bulk needs an explicit reindex afterwards.
Querying with relevance in mind
A multi-match query searches several fields at once, and a boost makes a hit in the name count for more than a hit in the description.
results = ProductDocument.search().query(
"multi_match",
query=term,
fields=["name^3", "sku^2", "description"],
fuzziness="AUTO",
)
Relevance is the whole point
Field boosts and fuzziness are not extras. They are the reason to use a search engine at all. A user who types a slightly wrong stock keeping unit (SKU) should still find the product, and the closest match should sit at the top.
Elasticsearch is a secondary store
The database remains the source of truth. The index can lag, and it can be thrown away and rebuilt at any time. Never make a write decision based on a search result. Read from search, write against the database.
Operational notes
Keep a management command that rebuilds the index from scratch. Any change to the mapping, such as a new field or a changed analyzer, means creating a fresh index and reindexing into it. Plan for that rebuild rather than being surprised by it.