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