Spec-Zone.ru › Django 3.2

Поиск

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

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

Варианты использования

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

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

>>> 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>]

Теперь у нас другая проблема — более длинное имя «Елена Бонем Картер» не отображается, так как оно намного длиннее. Поиск триграмм рассматривает все комбинации из трёх букв и сравнивает количество совпадений в строках поиска и исходных данных. Для более длинного имени существует больше комбинаций, которые не появляются в исходной строке, поэтому оно больше не считается близким совпадением.

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

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

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

  • Игнорирование «стоп-слов», таких как «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/3.1/topics/db/search/

Spec-Zone.ru

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