Spec-Zone.ru › Django 6.0

Поиск

Одна из распространённых задач веб-приложений — поиск данных в базе данных по пользовательскому вводу. В простом случае это может быть фильтрация списка объектов по категории. Для более сложного сценария могут потребоваться поиск с весовыми коэффициентами, категоризация, подсветка, поддержка нескольких языков и так далее. В этом документе описаны некоторые возможные сценарии использования и инструменты, которые можно применять.

Мы будем использовать те же модели, что и в документе Выполнение запросов.

Сценарии использования

Стандартные текстовые запросы

Для текстовых полей доступен ряд операций сопоставления. Например, вы можете разрешить поиск автора следующим образом:

>>> Author.objects.filter(name__contains="Terry")
[<Author: Terry Gilliam>, <Author: Terry Jones>]

Это очень ненадёжное решение, поскольку пользователю необходимо знать точную подстроку имени автора. Лучше может подойти поиск без учёта регистра (icontains), но он лишь немногим лучше.

Более продвинутые функции сравнения базы данных

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

Поиск в других базах данных

Все инструменты поиска, предоставляемые django.contrib.postgres, полностью построены на общедоступных API, таких как пользовательские средства поиска и функции базы данных. В зависимости от используемой базы данных вы сможете составить запросы, предоставляющие аналогичные API. Если какие-либо задачи невозможно решить таким способом, создайте тикет.

В примере выше мы выяснили, что поиск без учёта регистра был бы полезнее. При работе с именами на других языках можно улучшить поиск, используя unaccented comparison:

>>> Author.objects.filter(name__unaccent__icontains="Helen")
[<Author: Helen Mirren>, <Author: Helena Bonham Carter>, <Author: Hélène Joy>]

Здесь возникает ещё одна проблема: мы сопоставляем имя с другим вариантом написания. Однако в этом случае есть асимметрия — поиск по запросу Helen найдёт Helena или Hélène, но не наоборот. Другой вариант — использовать сравнение trigram_similar, которое сравнивает последовательности букв.

Например:

>>> Author.objects.filter(name__unaccent__lower__trigram_similar="Hélène")
[<Author: Helen Mirren>, <Author: Hélène Joy>]

Теперь возникает другая проблема: более длинное имя «Helena Bonham Carter» не отображается, поскольку оно значительно длиннее. При поиске по триграммам рассматриваются все сочетания из трёх букв и сравнивается, сколько из них встречается как в поисковом запросе, так и в исходной строке. Для более длинного имени больше сочетаний отсутствует в исходной строке, поэтому оно больше не считается близким совпадением.

Выбор подходящих функций сравнения зависит от конкретного набора данных, например от используемых языков и типа текста, по которому выполняется поиск. Все рассмотренные примеры относятся к коротким строкам, где пользователь, скорее всего, введёт что-то близкое (в зависимости от определения близости) к исходным данным.

Поиск по документам

Стандартные операции с базой данных перестают быть полезным решением, когда речь заходит о больших блоках текста. Примеры выше можно рассматривать как операции над строкой символов, тогда как при полнотекстовом поиске анализируются сами слова. В зависимости от используемой системы, она, вероятно, применяет некоторые из следующих подходов:

  • Игнорирование «стоп-слов», таких как «a», «the», «and».
  • Стемминг слов, чтобы «pony» и «ponies» считались похожими.
  • Назначение словам весовых коэффициентов на основе различных критериев, например частоты их появления в тексте или важности полей, в которых они встречаются, таких как заголовок или ключевые слова.

Для использования поискового программного обеспечения существует множество вариантов. Среди наиболее известных — Elastic и Solr. Это решения для полнотекстового поиска по документам. Чтобы использовать их с данными из моделей Django, потребуется слой, преобразующий ваши данные в текстовый документ и включающий ссылки на идентификаторы записей в базе данных. Когда поисковая система возвращает документ, его можно найти в базе данных. Для упрощения этого процесса существуют различные сторонние библиотеки.

Поддержка PostgreSQL

В PostgreSQL встроена собственная реализация полнотекстового поиска. Хотя она не так мощна, как некоторые другие поисковые системы, у неё есть преимущество: она работает непосредственно в базе данных, поэтому её легко сочетать с другими реляционными запросами, например с категоризацией.

Модуль django.contrib.postgres предоставляет вспомогательные средства для таких запросов. Например, запрос может выбрать все записи блога, в которых упоминается «сыр»:

>>> Entry.objects.filter(body_text__search="cheese")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]

Также можно фильтровать по сочетанию полей и по связанным моделям:

>>> Entry.objects.annotate(
...     search=SearchVector("blog__tagline", "body_text"),
... ).filter(search="cheese")
[
    <Entry: Cheese on Toast recipes>,
    <Entry: Pizza Recipes>,
    <Entry: Dairy farming in Argentina>,
]

Полное описание см. в документе contrib.postgres Полнотекстовый поиск.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/6.0/topics/db/search/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API