Поиск
Одной из распространенных задач веб-приложений является поиск данных в базе данных с использованием пользовательского ввода. В простом случае это может быть фильтрация списка объектов по категории. Более сложный случай может потребовать поиска с весами, категоризацией, выделением, несколькими языками и т. д. В этом документе описываются некоторые возможные варианты использования и инструменты, которые вы можете использовать.
Мы будем ссылаться на те же модели, что и в Создании запросов.
Варианты использования
Стандартные текстовые запросы
Для текстовых полей доступен набор операций сопоставления. Например, вы можете разрешить поиск автора следующим образом:
>>> 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.0/topics/db/search/