Поиск
Поиск набора запросов
Поиск Wagtail основан на API набора запросов Django. Вы должны иметь возможность выполнить поиск в любом наборе запросов Django при условии, что модель и поля, по которым выполняется фильтрация, добавлены в индекс поиска.
Поиск страниц
Wagtail предоставляет сокращение для поиска страниц: метод .search() QuerySet. Вы можете вызвать его для любого PageQuerySet. Например:
# Search future EventPages
>>> from wagtail.models import EventPage
>>> EventPage.objects.filter(date__gt=timezone.now()).search("Hello world!")
Все остальные методы PageQuerySet могут быть использованы с search(). Например:
# Search all live EventPages that are under the events index
>>> EventPage.objects.live().descendant_of(events_index).search("Event")
[<EventPage: Event 1>, <EventPage: Event 2>]
Примечание
Метод search() преобразует ваш QuerySet в экземпляр одного из классов SearchResults Wagtail (в зависимости от бэкенда). Это означает, что вы должны выполнить фильтрацию перед вызовом search().
До введения метода autocomplete(), метод поиска также выполнял частичное соответствие. Это поведение будет устаревшим, и вы должны либо перейти к новому методу autocomplete(), либо передать partial_match=False в метод поиска, чтобы включить новое поведение. Частичное соответствие в search() будет полностью удалено в будущей версии.
Поиск автозавершения
Wagtail предоставляет отдельный метод, который выполняет частичное соответствие для определенных полей автозавершения. Это полезно для предложения страниц пользователю в режиме реального времени по мере ввода запроса.
>>> EventPage.objects.live().autocomplete("Eve")
[<EventPage: Event 1>, <EventPage: Event 2>]
Примечание
Этот метод следует использовать только для автозавершения в режиме реального времени, и все реальные запросы поиска должны всегда использовать метод search().
Поиск изображений, документов и пользовательских моделей
Модели документов и изображений Wagtail предоставляют метод search в их наборах запросов, как и страницы:
>>> from wagtail.images.models import Image
>>> Image.objects.filter(uploaded_by_user=user).search("Hello")
[<Image: Hello>, <Image: Hello world!>]
Пользовательские модели можно искать, используя метод search непосредственно в бэкенде поиска:
>>> from myapp.models import Book
>>> from wagtail.search.backends import get_search_backend
# Search books
>>> s = get_search_backend()
>>> s.search("Great", Book)
[<Book: Great Expectations>, <Book: The Great Gatsby>]
Вы также можете передать набор запросов в метод search, что позволит вам добавлять фильтры к результатам поиска:
>>> from myapp.models import Book
>>> from wagtail.search.backends import get_search_backend
# Search books
>>> s = get_search_backend()
>>> s.search("Great", Book.objects.filter(published_date__year__lt=1900))
[<Book: Great Expectations>]
Указание полей для поиска
По умолчанию Wagtail будет искать все поля, которые были индексированы с помощью index.SearchField.
Это можно ограничить определенным набором полей, используя ключевое слово fields:
# Search just the title field
>>> EventPage.objects.search("Event", fields=["title"])
[<EventPage: Event 1>, <EventPage: Event 2>]
Многомерный поиск
Wagtail поддерживает многомерный поиск, который представляет собой вид фильтрации на основе поля классификации (например, категории или типа страницы).
Метод .facet(field_name) возвращает OrderedDict . Ключи — это идентификаторы связанных объектов, на которые ссылается указанное поле, а значения — это количество найденных ссылок для каждого идентификатора. Результаты упорядочены по количеству ссылок по убыванию.
Например, чтобы найти наиболее распространенные типы страниц в результатах поиска:
>>> Page.objects.search("Test").facet("content_type_id")
# Note: The keys correspond to the ID of a ContentType object; the values are the
# number of pages returned for that type
OrderedDict([
('2', 4), # 4 pages have content_type_id == 2
('1', 2), # 2 pages have content_type_id == 1
])
Изменение поведения поиска
Оператор поиска
Оператор поиска определяет, как должен вести себя поиск, когда пользователь ввел несколько поисковых терминов. Существует две возможные значения:
- “or” — результаты должны соответствовать хотя бы одному термину (по умолчанию для Elasticsearch)
- “and” — результаты должны соответствовать всем терминам (по умолчанию для поиска в базе данных)
Оба оператора имеют свои преимущества и недостатки. Оператор «or» вернет больше результатов, но, вероятно, будет содержать много результатов, которые не будут релевантными. Оператор «and» возвращает только результаты, содержащие все поисковые термины, но требует от пользователя более точного запроса.
Мы рекомендуем использовать оператор «or» при упорядочивании по релевантности и оператор «and» при упорядочивании по чему-либо другому (примечание: бэкенд базы данных в настоящее время не поддерживает упорядочивание по релевантности).
Вот пример использования ключевого слова operator:
# The database contains a "Thing" model with the following items:
# - Hello world
# - Hello
# - World
# Search with the "or" operator
>>> s = get_search_backend()
>>> s.search("Hello world", Things, operator="or")
# All records returned as they all contain either "hello" or "world"
[<Thing: Hello World>, <Thing: Hello>, <Thing: World>]
# Search with the "and" operator
>>> s = get_search_backend()
>>> s.search("Hello world", Things, operator="and")
# Only "hello world" returned as that's the only item that contains both terms
[<Thing: Hello world>]
Для моделей страниц, изображений и документов также поддерживается ключевое слово operator в методе search набора запросов:
>>> Page.objects.search("Hello world", operator="or")
# All pages containing either "hello" or "world" are returned
[<Page: Hello World>, <Page: Hello>, <Page: World>]
Поиск по фразам
Поиск по фразам используется для поиска целых предложений или фраз, а не отдельных терминов. Термины должны появляться вместе и в том же порядке.
Например:
>>> from wagtail.search.query import Phrase
>>> Page.objects.search(Phrase("Hello world"))
[<Page: Hello World>]
>>> Page.objects.search(Phrase("World hello"))
[<Page: World Hello day>]
Если вы хотите реализовать запросы с фразами с использованием синтаксиса двойных кавычек, см. Разбор строки запроса.
Нечеткое соответствие
Новое в версии 4.0.
Нечеткое соответствие вернет документы, содержащие термины, похожие на поисковой термин, по показателю расстояния редактирования Левенштейна.
Для терминов длиной от трех до пяти букв допускается не более одного исправления (транспозиции, вставки или удаления символа), для более длинных терминов — два исправления, а для более коротких терминов необходимо точное соответствие.
Например:
>>> from wagtail.search.query import Fuzzy
>>> Page.objects.search(Fuzzy("Hallo"))
[<Page: Hello World>]
Нечеткое соответствие поддерживается только бэкендом поиска Elasticsearch.
Сложные поисковые запросы
С помощью классов запросов поиска Wagtail также поддерживает создание поисковых запросов в виде объектов Python, которые могут быть обернуты и объединены с другими поисковыми запросами. Доступны следующие классы:
PlainText(query_string, operator=None, boost=1.0)
Этот класс оборачивает строку отдельных терминов. Это то же самое, что поиск без классов запросов.
Он принимает строку запроса, оператор и коэффициент.
Например:
>>> from wagtail.search.query import PlainText
>>> Page.objects.search(PlainText("Hello world"))
# Multiple plain text queries can be combined. This example will match both "hello world" and "Hello earth"
>>> Page.objects.search(PlainText("Hello") & (PlainText("world") | PlainText("earth")))
Phrase(query_string)
Этот класс оборачивает строку, содержащую фразу. См. предыдущий раздел, чтобы узнать, как это работает.
Например:
# This example will match both the phrases "hello world" and "Hello earth"
>>> Page.objects.search(Phrase("Hello world") | Phrase("Hello earth"))
Boost(query, boost)
Этот класс повышает рейтинг другого запроса.
Например:
>>> from wagtail.search.query import PlainText, Boost
# This example will match both the phrases "hello world" and "Hello earth" but matches for "hello world" will be ranked higher
>>> Page.objects.search(Boost(Phrase("Hello world"), 10.0) | Phrase("Hello earth"))
Обратите внимание, что это не поддерживается бэкендами поиска PostgreSQL или баз данных.
Разбор строки запроса
Предыдущие разделы показывают, как вручную создать запрос поиска по фразе, но многие поисковые системы (включая административную панель Wagtail, попробуйте!) поддерживают запись запросов поиска по фразе, обернув фразу двойными кавычками. Помимо фраз, вы можете также разрешить пользователям добавлять фильтры в запрос, используя синтаксис двоеточия (hello world published:yes).
Эти две возможности могут быть реализованы с помощью утилиты parse_query_string. Эта функция принимает строку запроса, введенную пользователем, и возвращает объект запроса и словарь фильтров:
Например:
>>> from wagtail.search.utils import parse_query_string
>>> filters, query = parse_query_string('my query string "this is a phrase" this-is-a:filter', operator='and')
>>> filters
{
'this-is-a': 'filter',
}
>>> query
And([
PlainText("my query string", operator='and'),
Phrase("this is a phrase"),
])
Вот пример того, как эта функция может быть использована в представлении поиска:
from wagtail.search.utils import parse_query_string
def search(request):
query_string = request.GET['query']
# Parse query
filters, query = parse_query_string(query_string, operator='and')
# Published filter
# An example filter that accepts either `published:yes` or `published:no` and filters the pages accordingly
published_filter = filters.get('published')
published_filter = published_filter and published_filter.lower()
if published_filter in ['yes', 'true']:
pages = pages.filter(live=True)
elif published_filter in ['no', 'false']:
pages = pages.filter(live=False)
# Search
pages = pages.search(query)
return render(request, 'search_results.html', {'pages': pages})
Настройка порядка
По умолчанию результаты поиска упорядочиваются по релевантности, если бэкенд это поддерживает. Чтобы сохранить существующий порядок набора запросов, необходимо установить ключевое слово order_by_relevance на False в методе search().
Например:
# Get a list of events ordered by date
>>> EventPage.objects.order_by('date').search("Event", order_by_relevance=False)
# Events ordered by date
[<EventPage: Easter>, <EventPage: Halloween>, <EventPage: Christmas>]
Добавление оценки к результатам
Для каждого совпавшего результата Elasticsearch вычисляет «оценку», которая представляет собой число, показывающее, насколько релевантен результат в соответствии с запросом пользователя. Результаты обычно упорядочиваются на основе оценки.
В некоторых случаях полезно иметь доступ к оценке (например, для программного объединения двух запросов для разных моделей). Вы можете добавить оценку к каждому результату, вызвав метод .annotate_score(field) в SearchQuerySet.
Например:
>>> events = EventPage.objects.search("Event").annotate_score("_score")
>>> for event in events:
... print(event.title, event._score)
...
("Easter", 2.5),
("Halloween", 1.7),
("Christmas", 1.5),
Обратите внимание, что сама оценка является условной и полезна только для сравнения результатов для одного и того же запроса.
Пример представления страницы поиска
Вот пример представления Django, которое можно использовать для добавления страницы «поиск» на ваш сайт:
# views.py
from django.shortcuts import render
from wagtail.models import Page
from wagtail.search.models import Query
def search(request):
# Search
search_query = request.GET.get('query', None)
if search_query:
search_results = Page.objects.live().search(search_query)
# Log the query so Wagtail can suggest promoted results
Query.get(search_query).add_hit()
else:
search_results = Page.objects.none()
# Render template
return render(request, 'search_results.html', {
'search_query': search_query,
'search_results': search_results,
})
И вот шаблон, который к нему прилагается:
{% extends "base.html" %}
{% load wagtailcore_tags %}
{% block title %}Search{% endblock %}
{% block content %}
<form action="{% url 'search' %}" method="get">
<input type="text" name="query" value="{{ search_query }}">
<input type="submit" value="Search">
</form>
{% if search_results %}
<ul>
{% for result in search_results %}
<li>
<h4><a href="{% pageurl result %}">{{ result }}</a></h4>
{% if result.search_description %}
{{ result.search_description|safe }}
{% endif %}
</li>
{% endfor %}
</ul>
{% elif search_query %}
No results found
{% else %}
Please type something into the search box
{% endif %}
{% endblock %}
Рекомендуемые результаты поиска
«Рекомендуемые результаты поиска» позволяют редакторам явно связывать релевантный контент с поисковыми запросами, поэтому страницы результатов могут содержать отобранный контент в дополнение к результатам из поисковой системы.
Эта функциональность предоставляется модулем search_promotions contrib.
© 2014-present Torchbox Ltd and individual contributors.
All rights are reserved.
Licensed under the BSD License.
https://docs.wagtail.org/en/stable/topics/search/searching.html