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