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