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