Spec-Zone.ru › Django 3.2

Полнотекстовый поиск

Функции базы данных в модуле django.contrib.postgres.search облегчают использование движка полнотекстового поиска PostgreSQL полнотекстового поиска.

В примерах этого документа мы будем использовать модели, определённые в Создание запросов.

См. также

Для общего обзора поиска см. документацию по теме.

Поиск search

Распространённый способ использования полнотекстового поиска — поиск одного термина в одном столбце базы данных. Например:

>>> Entry.objects.filter(body_text__search='Cheese')
[<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]

Это создаёт to_tsvector в базе данных из поля body_text и plainto_tsquery из поискового термина 'Cheese', оба с использованием стандартной конфигурации поиска базы данных. Результаты получаются путём сопоставления запроса и вектора.

Чтобы использовать поиск search, 'django.contrib.postgres' должен быть в вашем INSTALLED_APPS.

Изменено в Django 3.1:

Добавлена поддержка выражений запроса.

SearchVector

class SearchVector(*expressions, config=None, weight=None)

Поиск по одному полю удобен, но ограничен. Экземпляры Entry, которые мы ищем, принадлежат Blog, у которого есть поле tagline. Чтобы выполнить запрос по обоим полям, используйте SearchVector.

>>> from django.contrib.postgres.search import SearchVector
>>> Entry.objects.annotate(
...     search=SearchVector('body_text', 'blog__tagline'),
... ).filter(search='Cheese')
[<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]

Аргументы для SearchVector могут быть любыми Expression или именем поля. Несколько аргументов будут конкатенированы с помощью пробела, чтобы поисковый документ включал их все.

SearchVector объекты могут быть объединены вместе, позволяя их повторное использование. Например:

>>> Entry.objects.annotate(
...     search=SearchVector('body_text') + SearchVector('blog__tagline'),
... ).filter(search='Cheese')
[<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]

См. Изменение конфигурации поиска и Взвешивание запросов для объяснения параметров config и weight.

SearchQuery

class SearchQuery(value, config=None, search_type='plain')

SearchQuery преобразует предоставленные пользователем термины в объект поискового запроса, который база данных сравнивает с вектором поиска. По умолчанию все предоставленные пользователем слова проходят через алгоритмы стемминга, а затем ищется соответствие всем получившимся терминам.

Если search_type равно 'plain', что является значением по умолчанию, термины обрабатываются как отдельные ключевые слова. Если search_type равно 'phrase', термины обрабатываются как единая фраза. Если search_type равно 'raw', вы можете указать отформатированный поисковый запрос с терминами и операторами. Если search_type равно 'websearch', вы можете указать отформатированный поисковый запрос, аналогичный используемому поисковыми системами в интернете. 'websearch' требует PostgreSQL ≥ 11. Прочитайте документацию PostgreSQL по полнотекстовому поиску, чтобы узнать о различиях и синтаксисе. Примеры:

>>> from django.contrib.postgres.search import SearchQuery
>>> SearchQuery('red tomato')  # two keywords
>>> SearchQuery('tomato red')  # same results as above
>>> SearchQuery('red tomato', search_type='phrase')  # a phrase
>>> SearchQuery('tomato red', search_type='phrase')  # a different phrase
>>> SearchQuery("'tomato' & ('red' | 'green')", search_type='raw')  # boolean operators
>>> SearchQuery("'tomato' ('red' OR 'green')", search_type='websearch')  # websearch operators

SearchQuery термины могут быть логически объединены для большей гибкости:

>>> from django.contrib.postgres.search import SearchQuery
>>> SearchQuery('meat') & SearchQuery('cheese')  # AND
>>> SearchQuery('meat') | SearchQuery('cheese')  # OR
>>> ~SearchQuery('meat')  # NOT

См. Изменение конфигурации поиска для объяснения параметра config.

Изменено в Django 3.1:

Добавлена поддержка типа поиска 'websearch' и выражений запроса в SearchQuery.value.

SearchRank

class SearchRank(vector, query, weights=None, normalization=None, cover_density=False)

До сих пор мы возвращали результаты, для которых возможно любое совпадение между вектором и запросом. Вероятно, вам потребуется отсортировать результаты по степени релевантности. PostgreSQL предоставляет функцию ранжирования, которая учитывает частоту появления поисковых терминов в документе, близость терминов в документе и важность части документа, где они встречаются. Чем лучше совпадение, тем выше значение ранга. Для сортировки по релевантности:

>>> from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
>>> vector = SearchVector('body_text')
>>> query = SearchQuery('cheese')
>>> Entry.objects.annotate(rank=SearchRank(vector, query)).order_by('-rank')
[<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]

См. Взвешивание запросов для объяснения параметра weights.

Установите параметр cover_density в значение True, чтобы включить ранжирование по плотности покрытия, что означает, что учитывается близость сопоставляемых поисковых терминов.

Укажите целое число параметру normalization для управления нормализацией ранга. Это целое число — битовая маска, поэтому вы можете объединить несколько поведений:

>>> from django.db.models import Value
>>> Entry.objects.annotate(
...     rank=SearchRank(
...         vector,
...         query,
...         normalization=Value(2).bitor(Value(4)),
...     )
... )

Документация PostgreSQL содержит более подробную информацию о различных вариантах нормализации ранга.

Добавлено в Django 3.1:

Были добавлены параметры normalization и cover_density.

SearchHeadline

Добавлено в Django 3.1.
class SearchHeadline(expression, query, config=None, start_sel=None, stop_sel=None, max_words=None, min_words=None, short_word=None, highlight_all=None, max_fragments=None, fragment_delimiter=None)

Принимает одно текстовое поле или выражение, запрос, конфигурацию и набор опций. Возвращает результаты поиска с выделением.

Установите параметры start_sel и stop_sel в строковые значения, используемые для обертывания выделенных поисковых терминов в документе. Значения по умолчанию PostgreSQL — <b> и </b>.

Укажите целые значения для параметров max_words и min_words для определения наибольшей и наименьшей длин заголовков. Значения по умолчанию PostgreSQL — 35 и 15.

Укажите целое значение для параметра short_word для отбрасывания слов данной длины или меньше в каждом заголовке. Значение по умолчанию PostgreSQL — 3.

Установите параметр highlight_all в значение True, чтобы использовать весь документ вместо фрагмента и игнорировать параметры max_words, min_words и short_word. По умолчанию в PostgreSQL это отключено.

Укажите ненулевое целое значение для параметра max_fragments для установки максимального числа отображаемых фрагментов. По умолчанию в PostgreSQL это отключено.

Установите строковый параметр fragment_delimiter для настройки разделителя между фрагментами. Значение по умолчанию PostgreSQL — " ... ".

Документация PostgreSQL содержит более подробную информацию о выделении результатов поиска.

Пример использования:

>>> from django.contrib.postgres.search import SearchHeadline, SearchQuery
>>> query = SearchQuery('red tomato')
>>> entry = Entry.objects.annotate(
...     headline=SearchHeadline(
...         'body_text',
...         query,
...         start_sel='<span>',
...         stop_sel='</span>',
...     ),
... ).get()
>>> print(entry.headline)
Sandwich with <span>tomato</span> and <span>red</span> cheese.

См. Изменение конфигурации поиска для объяснения параметра config.

Изменение конфигурации поиска

Вы можете указать атрибут config для SearchVector и SearchQuery для использования другой конфигурации поиска. Это позволяет использовать разные анализаторы языка и словари, определённые в базе данных:

>>> from django.contrib.postgres.search import SearchQuery, SearchVector
>>> Entry.objects.annotate(
...     search=SearchVector('body_text', config='french'),
... ).filter(search=SearchQuery('œuf', config='french'))
[<Entry: Pain perdu>]

Значение config также может храниться в другом столбце:

>>> from django.db.models import F
>>> Entry.objects.annotate(
...     search=SearchVector('body_text', config=F('blog__language')),
... ).filter(search=SearchQuery('œuf', config=F('blog__language')))
[<Entry: Pain perdu>]

Взвешивание запросов

Возможно, не все поля имеют одинаковую релевантность в запросе, поэтому можно установить веса различных векторов до их объединения:

>>> from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
>>> vector = SearchVector('body_text', weight='A') + SearchVector('blog__tagline', weight='B')
>>> query = SearchQuery('cheese')
>>> Entry.objects.annotate(rank=SearchRank(vector, query)).filter(rank__gte=0.3).order_by('rank')

Вес должен быть одной из следующих букв: D, C, B, A. По умолчанию эти веса соответствуют числам 0.1, 0.2, 0.4, и 1.0, соответственно. Если вы хотите задать другие веса, передайте список из четырёх чисел с плавающей точкой в SearchRank как weights в том же порядке, что и выше:

>>> rank = SearchRank(vector, query, weights=[0.2, 0.4, 0.6, 0.8])
>>> Entry.objects.annotate(rank=rank).filter(rank__gte=0.3).order_by('-rank')

Производительность

Специальная настройка базы данных не требуется для использования этих функций, однако, если вы ищете более чем в нескольких сотнях записей, вы, вероятно, столкнётесь с проблемами производительности. Полнотекстовый поиск — более ресурсоёмкий процесс, чем, например, сравнение размеров целого числа.

Если все поля, по которым вы выполняете поиск, находятся в одной модели, вы можете создать функциональный индекс, который соответствует вектору поиска, который вы хотите использовать. Документация PostgreSQL содержит информацию о создании индексов для полнотекстового поиска.

SearchVectorField

class SearchVectorField

Если этот подход становится слишком медленным, вы можете добавить SearchVectorField в свою модель. Вам нужно будет поддерживать его заполнение с помощью триггеров, например, как описано в документации PostgreSQL. Затем вы можете выполнить запрос к полю, как будто это был аннотированный SearchVector:

>>> Entry.objects.update(search_vector=SearchVector('body_text'))
>>> Entry.objects.filter(search_vector='cheese')
[<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]

Сходство триграмм

Другой подход к поиску — сходство триграмм. Триграмма — это группа из трёх последовательных символов. В дополнение к trigram_similar поиску, вы можете использовать несколько других выражений.

END_OF_DOCUMENT_MARKER

Для их использования необходимо активировать расширение pg_trgm в PostgreSQL. Вы можете установить его, используя операцию миграции TrigramExtension.

TrigramSimilarity

class TrigramSimilarity(expression, string, **extra)

Принимает имя поля или выражение и строку или выражение. Возвращает триграмную схожесть между двумя аргументами.

Пример использования:

>>> from django.contrib.postgres.search import TrigramSimilarity
>>> Author.objects.create(name='Katy Stevens')
>>> Author.objects.create(name='Stephen Keats')
>>> test = 'Katie Stephens'
>>> Author.objects.annotate(
...     similarity=TrigramSimilarity('name', test),
... ).filter(similarity__gt=0.3).order_by('-similarity')
[<Author: Katy Stevens>, <Author: Stephen Keats>]

TrigramDistance

class TrigramDistance(expression, string, **extra)

Принимает имя поля или выражение и строку или выражение. Возвращает триграмное расстояние между двумя аргументами.

Пример использования:

>>> from django.contrib.postgres.search import TrigramDistance
>>> Author.objects.create(name='Katy Stevens')
>>> Author.objects.create(name='Stephen Keats')
>>> test = 'Katie Stephens'
>>> Author.objects.annotate(
...     distance=TrigramDistance('name', test),
... ).filter(distance__lte=0.7).order_by('distance')
[<Author: Katy Stevens>, <Author: Stephen Keats>]

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/3.2/ref/contrib/postgres/search/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API