Spec-Zone.ru › Django 5.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', вы можете предоставить отформатированный поисковый запрос с терминами и операторами. Если 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.

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 содержатся более подробные сведения о различных вариантах нормализации рангов.

SearchHeadline

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")

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

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

В случае, если все поля, по которым вы осуществляете поиск, находятся в одной модели, вы можете создать функциональный GIN или GiST индекс, соответствующий вектору поиска, который вы хотите использовать. Например:

GinIndex(
    SearchVector("body_text", "headline", config="english"),
    name="search_vector_idx",
)

В документации 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, trigram_word_similar и trigram_strict_word_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>]

TrigramWordSimilarity

class TrigramWordSimilarity(string, expression, **extra)

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

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

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

TrigramStrictWordSimilarity

class TrigramStrictWordSimilarity(string, expression, **extra)
Новое в Django 4.2.

Принимает строку или выражение и имя поля или выражение. Возвращает строгое сходство триграмм слов между двумя аргументами. Аналогично TrigramWordSimilarity(), за исключением того, что она принудительно задаёт границы совпадения границам слов.

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>]

TrigramWordDistance

class TrigramWordDistance(string, expression, **extra)

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

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

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

TrigramStrictWordDistance

class TrigramStrictWordDistance(string, expression, **extra)
Новое в Django 4.2.

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

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

Spec-Zone.ru

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