Полный поиск по тексту
Функции базы данных в модуле 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)[source]
Поиск по одному полю — это здорово, но довольно ограниченно. Экземпляры 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)[source]
SearchQuery преобразует предоставленные пользователем термины в объект запроса поиска, который база данных сравнивает с вектором поиска. По умолчанию все слова, предоставленные пользователем, передаются через алгоритмы стемминга, а затем ищутся совпадения для всех полученных терминов.
Термины SearchQuery могут логически объединяться для большей гибкости:
>>> from django.contrib.postgres.search import SearchQuery
>>> SearchQuery('potato') & SearchQuery('ireland') # potato AND ireland
>>> SearchQuery('potato') | SearchQuery('penguin') # potato OR penguin
>>> ~SearchQuery('sausage') # NOT sausage
См. Изменение конфигурации поиска для объяснения параметра config.
SearchRank
-
class SearchRank(vector, query, weights=None)[source]
Пока мы просто возвращаем результаты, для которых возможно любое соответствие между вектором и запросом. Вероятно, вы захотите упорядочить результаты по какой-либо степени релевантности. 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[source]
Если этот подход становится слишком медленным, вы можете добавить 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)[source]
Принимает имя поля или выражение и строку или выражение. Возвращает сходство триграмм между двумя аргументами.
Пример использования:
>>> 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)[source]
Принимает имя поля или выражение и строку или выражение. Возвращает расстояние триграмм между двумя аргументами.
Пример использования:
>>> 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/1.10/ref/contrib/postgres/search/