Зачем полнотекстовый поиск

В уроке про пагинацию и поиск был простой пример SearchVector. Здесь мы углубляемся: config, ранжирование, GinIndex, trigram и подсветка.

icontains ищет подстроку в каждой строке. shoes и shoe для него разные слова, порядка результатов нет, а на большой таблице идёт полный скан. PostgreSQL же превращает текст в лексемы:

sql
SELECT to_tsvector('english', 'Running shoes for runners');
-- 'run':1,5 'shoe':2

SELECT websearch_to_tsquery('english', '"running shoes" -boots');
-- 'run' <-> 'shoe' & !'boot'
Статья, tsvector, GIN-индекс, tsquery и ранжирование
Статья, tsvector, GIN-индекс, tsquery и ранжирование

💡 Полнотекстовый поиск доступен только на PostgreSQL. Добавьте django.contrib.postgres в INSTALLED_APPS.

SearchVector и SearchQuery

python
# settings.py
INSTALLED_APPS = [
    # ...
    "django.contrib.postgres",
    "articles",
]

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME": "shop",
        # USER, PASSWORD, HOST from environment
    }
}
python
from django.contrib.postgres.search import SearchVector

from articles.models import Article

vector = SearchVector("title", "body", config="english")

found = Article.objects.annotate(search=vector).filter(search="django indexes")

config выбирает язык текста. Для вектора и запроса он должен совпадать, иначе лексемы могут не совпасть.

python
from django.contrib.postgres.search import SearchQuery

SearchQuery("red tomato")                          # plain: all words
SearchQuery("red tomato", search_type="phrase")    # words side by side
SearchQuery("red & tomato", search_type="raw")     # raw tsquery syntax
SearchQuery('"red tomato" -green', search_type="websearch")