Полнотекстовый поиск¶
Функции базы данных в модуле django.contrib.postgres.search
облегчают использование модуля PostgreSQL full text search engine.
Для примеров в этом документе мы будем использовать модели, определенные в Работа с запросами.
См.также
Высокоуровневый обзор поиска см. в topic documentation.
Поиск 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'
, то вы можете предоставить форматированный поисковый запрос с терминами и операторами. Прочитайте статью Full Text Search docs в 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
.
Добавлен параметр 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 есть подробная информация о creating indexes for full text search.
SearchVectorField
¶
-
class
SearchVectorField
[исходный код]¶
Если этот подход становится слишком медленным, вы можете добавить SearchVectorField
к вашей модели. Вам нужно будет поддерживать его заполненным триггерами, например, как описано в PostgreSQL documentation. Затем вы можете запрашивать поле, как если бы оно было аннотированным 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 extension на 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>]