Django 5 для начинающих

Прогресс по курсу:  9/1004

6.11 Добавление полнотекстового поиска в блог
4 из 4 шагов пройдено

Выделение основ слов и ранжирование результатов

Выделение основы слова, или стемминг,  это процесс приведения слов к их словообразовательной базе, основанию или корневой форме.

Стемминг используется поисковыми системами для редуцирования индексированных слов до их основы и для того, чтобы иметь возможность сопоставлять изменяемые или производные слова. Например, слова music, musical и musicality поисковая система может считать похожими словами.

В процессе выделения основы каждый поисковый токен нормализуется в лексему, или единицу лексического значения, которая лежит в основе набора слов, связанных посредством флексии. При создании поискового запроса слова music, musical и musicality будут преобразованы в music.

Django предоставляет класс SearchQuery, чтобы транслировать термины в объект поискового запроса. По умолчанию термины пропускаются через базовые алгоритмы выделения основ слов, что помогает получать более оптимальные совпадения.

Поисковый механизм PostgreSQL также удаляет стоп-слова, такие как a, the, on и of.
Стоп-слова – это коллекция часто используемых слов в языке. Они удаляются при создании поискового запроса, поскольку появляются слишком часто, чтобы быть релевантными для поисковых запросов.

Список стоп-слов, используемых PostgreSQL для английского языка, находится на странице https://github.com/postgres/postgres/blob/master/src/backend/snow-ball/stopwords/english.stop.

Мы также хотим упорядочивать результаты по релевантности. PostgreSQL предоставляет функцию ранжирования, которая упорядочивает результаты на основе частоты появления терминов запроса и степени их близости друг к другу.

Отредактируйте файл views.py приложения blog, добавив следующую ниже инструкцию импорта:

from django.contrib.postgres.search import SearchVector, SearchQuery, SearchRank

Затем отредактируйте представление post_search, как показано ниже:

def post_search(request):
    form = SearchForm()
    query = None
    results = []

    if 'query' in request.GET:
        form = SearchForm(request.GET)
        if form.is_valid():
            query = form.cleaned_data['query']
            search_vector = SearchVector('title', 'body')
            search_query = SearchQuery(query)
            results = Post.published.annotate(
                search=search_vector,
                rank=SearchRank(search_vector, search_query)
            ).filter(search=search_query).order_by('-rank')

    return render(request,
                  'blog/post/search.html',
                  {'form': form,
                   'query': query,
                   'results': results})

В приведенном выше исходном коде создается объект SearchQuery, по нему фильтруются результаты, и для упорядочивания результатов по релевантности используется SearchRank.

Теперь можно перейти по адресу http://127.0.0.1:8000/blog/search/ в своем браузере и протестировать различные поисковые запросы, чтобы проверить выделение основ слов и ранжирование.

Ниже приведен пример ранжирования по числу появлений слова django в заголовке и теле постов:

Выделение основ слов и удаление стоп-слов на разных языках

Объекты SearchVector и SearchQuery можно настроить под исполнение процедур выделения основ слов и удаления стоп-слов на любом языке.

Для того чтобы использовать другую конфигурацию поиска, в SearchVector и SearchQuery передается атрибут config.
Такой подход позволяет использовать разные языковые парсеры и словари.

В следующем ниже примере выделяются основы слов и удаляются стоп-слова на русском языке:

            search_vector = SearchVector('title', 'body', config='russian')
            search_query = SearchQuery(query, config='russian')
            results = Post.published.annotate(
                search=search_vector,
                rank=SearchRank(search_vector, search_query)
            ).filter(search=search_query).order_by('-rank')

Используемый в PostgreSQL словарь русских стоп-слов находится на странице https://github.com/postgres/postgres/blob/master/src/backend/snowball/stopwords/russian.stop

Все языки можете посмотреть по ссылке - https://github.com/postgres/postgres/tree/master/src/backend/snowball/stopwords


Будьте вежливы и соблюдайте наши принципы сообщества. Пожалуйста, не оставляйте решения и подсказки в комментариях, для этого есть отдельный форум.
Оставить комментарий

Возник вопрос: у меня в блоге есть посты с названиями 'adding something'. В процессе поиска по 'adding' они находятся, но если искать по 'add' выводит 'no results found'. Разве не должен запрос 'adding' преобразовываться в 'add' и искать вхождение 'add' в слово?

@Сак_Валентин, вижу, что в следующем шаге как раз, дорабатывается данный момент:)