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