Spec-Zone.ru › Django 3.0

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

Функции базы данных в модуле 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.

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', вы можете предоставить отформатированный поисковый запрос с терминами и операторами. Прочитайте документацию 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 термины могут быть логически объединены для повышения гибкости:

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

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

Введено в Django 2.2:

Был добавлен параметр search_type.

SearchRank

class SearchRank(vector, query, weights=None)

До сих пор мы возвращали результаты, для которых любое соответствие между вектором и запросом возможно. Вероятно, вам нужно будет упорядочить результаты по какой-то степени релевантности. 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.

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

Вы можете указать атрибут 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, вы можете использовать несколько других выражений.

Для их использования необходимо активировать расширение 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.0/ref/contrib/postgres/search/

Spec-Zone.ru

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