Блог на Django #35: Поисковые алгоритмы в Django

Сокращение и ранжирование результатов

Django предлагает класс SearchQuery для перевода запросов в объект поискового запроса. По умолчанию запросы проходят через алгоритмы сокращения, что позволяет лучше находить совпадения. Также можно отсортировать результаты по релевантности. PostgreSQL предоставляет функцию ранжирования, которая сортирует результаты на основе того, как часто текст запроса появляется и как близко они расположены относительно друг друга. Отредактируйте файл views.py приложения blog и добавьте следующие импорты:

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

Затем взгляните на эти строки:

results = Post.objects.annotate(
		search=SearchVector('title', 'body'), 
	  ).filter(search=query)

Замените их этими:

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

В этом коде создается объект SeatchQuery, после этого результаты фильтруются, а SearchRank используется для их ранжирования. Можете открыть https://127.0.0.1:8000/blog/search/ в браузере и провести несколько тестов, чтобы увидеть, как работает сокращение и ранжирование.

Вес запросов

Можно сделать так, чтобы у определенных направлений было больше веса при сортировке по релевантности. Например, такой код подойдет, чтобы ранжировать результаты в первую очередь по заголовкам, а не по телу. Отредактируйте предыдущие строки файла views.py приложения blog, чтобы он выглядел так:

search_vector = SearchVector('title', weight='A') + SearchVector('body', weight='B') 
search_query = SearchQuery(query) 
results = Post.objects.annotate( 
		rank=SearchRank(search_vector, search_query)
	  ).filter(rank__gte=0.3).order_by('-rank')

В этом коде используется дополнительный «вес» для направлений поиска в полях title и body. Вес по умолчанию — D, C, B и A. Они соответствуют числам 0.1, 0.2, 0.4 и 1.0 соответственно. Применим вес 1.0 к полю title и 0.4body: совпадения в заголовке будут преобладать над таковыми в теле. Отфильтруем результаты для отображения только тех, у которых вес больше 0.3.

Поиск по схожести триграмм

Еще один поисковый алгоритм — схожесть триграмм. Триграмма — это группа из трех символов. Можно измерить схожесть двух строк, посчитав количество общих триграмм. Этот подход часто используется для измерения схожести слов во многих языках.

Для использования триграмм в PostgreSQL нужно сперва установить pg_trgm. Используйте следующую команду, чтобы подключиться к базе данных:

psql blog

Затем эту, чтобы установить расширение pg_trgm:

CREATE EXTENSION pg_trgm;

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

from django.contrib.postgres.search import TrigramSimilarity

Затем замените поисковый запрос Post на следующие строки:

results = Post.objects.annotate(
		similarity=TrigramSimilarity('title', query), 
	  ).filter(similarity__gt=0.3).order_by('-similarity')

Откройте https://127.0.0.1:8000/blog/search/ в браузере и проверьте разные варианты поиска триграмм. Например, введите yango и получите результаты включающие слово django (есть в блоге есть статьи с таким словом).

Теперь у проекта мощный поисковый движок. Еще больше информации о полнотекстовом поиске можно найти здесь https://docs.djangoproject.com/en/2.0/ref/contrib/postgres/search/.