documentation migrate rest of topics/search/** to markdown

pull/8759/head
LB Johnston 2022-06-25 23:22:36 +10:00 zatwierdzone przez LB (Ben Johnston)
rodzic 7d2545cddc
commit 4e7accda55
3 zmienionych plików z 397 dodań i 465 usunięć

Wyświetl plik

@ -1,114 +1,98 @@
(wagtailsearch_backends)=
.. _wagtailsearch_backends:
========
Backends
========
# Backends
Wagtailsearch has support for multiple backends, giving you the choice between using the database for search or an external service such as Elasticsearch.
You can configure which backend to use with the ``WAGTAILSEARCH_BACKENDS`` setting:
.. code-block:: python
You can configure which backend to use with the `WAGTAILSEARCH_BACKENDS` setting:
```python
WAGTAILSEARCH_BACKENDS = {
'default': {
'BACKEND': 'wagtail.search.backends.database',
}
}
```
(wagtailsearch_backends_auto_update)=
.. _wagtailsearch_backends_auto_update:
``AUTO_UPDATE``
===============
## `AUTO_UPDATE`
By default, Wagtail will automatically keep all indexes up to date. This could impact performance when editing content, especially if your index is hosted on an external service.
The ``AUTO_UPDATE`` setting allows you to disable this on a per-index basis:
.. code-block:: python
The `AUTO_UPDATE` setting allows you to disable this on a per-index basis:
```python
WAGTAILSEARCH_BACKENDS = {
'default': {
'BACKEND': ...,
'AUTO_UPDATE': False,
}
}
```
If you have disabled auto update, you must run the :ref:`update_index` command on a regular basis to keep the index in sync with the database.
If you have disabled auto update, you must run the [](update_index) command on a regular basis to keep the index in sync with the database.
(wagtailsearch_backends_atomic_rebuild)=
.. _wagtailsearch_backends_atomic_rebuild:
## `ATOMIC_REBUILD`
``ATOMIC_REBUILD``
==================
```{warning}
This option may not work on Elasticsearch version 5.4.x, due to [a bug in the handling of aliases](https://github.com/elastic/elasticsearch/issues/24644) - please upgrade to 5.5 or later.
```
.. warning::
This option may not work on Elasticsearch version 5.4.x, due to `a bug in the handling of aliases <https://github.com/elastic/elasticsearch/issues/24644>`_ - please upgrade to 5.5 or later.
By default (when using the Elasticsearch backend), when the `update_index` command is run, Wagtail deletes the index and rebuilds it from scratch. This causes the search engine to not return results until the rebuild is complete and is also risky as you can't rollback if an error occurs.
By default (when using the Elasticsearch backend), when the ``update_index`` command is run, Wagtail deletes the index and rebuilds it from scratch. This causes the search engine to not return results until the rebuild is complete and is also risky as you can't rollback if an error occurs.
Setting the `ATOMIC_REBUILD` setting to `True` makes Wagtail rebuild into a separate index while keep the old index active until the new one is fully built. When the rebuild is finished, the indexes are swapped atomically and the old index is deleted.
Setting the ``ATOMIC_REBUILD`` setting to ``True`` makes Wagtail rebuild into a separate index while keep the old index active until the new one is fully built. When the rebuild is finished, the indexes are swapped atomically and the old index is deleted.
``BACKEND``
===========
## `BACKEND`
Here's a list of backends that Wagtail supports out of the box.
.. _wagtailsearch_backends_database:
(wagtailsearch_backends_database)=
Database Backend (default)
--------------------------
### Database Backend (default)
``wagtail.search.backends.database``
`wagtail.search.backends.database`
The database search backend searches content in the database using the full text search features of the database backend in use (such as PostgreSQL FTS, SQLite FTS5).
This backend is intended to be used for development and also should be good enough to use in production on sites that don't require any Elasticsearch specific features.
.. versionchanged:: 2.15
```{versionchanged} 2.15
`wagtail.search.backends.database` replaces the old `wagtail.search.backends.db` backend which works using simple substring matching only. `wagtail.search.backends.db` is still the default if `WAGTAILSEARCH_BACKENDS` is not specified; `wagtail.search.backends.database` will become the default in Wagtail 2.17.
```
``wagtail.search.backends.database`` replaces the old ``wagtail.search.backends.db`` backend which works using simple substring matching only. ``wagtail.search.backends.db`` is still the default if ``WAGTAILSEARCH_BACKENDS`` is not specified; ``wagtail.search.backends.database`` will become the default in Wagtail 2.17.
(wagtailsearch_backends_elasticsearch)=
.. _wagtailsearch_backends_elasticsearch:
Elasticsearch Backend
---------------------
### Elasticsearch Backend
Elasticsearch versions 5, 6 and 7 are supported. Use the appropriate backend for your version:
``wagtail.search.backends.elasticsearch5`` (Elasticsearch 5.x)
- `wagtail.search.backends.elasticsearch5` (Elasticsearch 5.x)
- `wagtail.search.backends.elasticsearch6` (Elasticsearch 6.x)
- `wagtail.search.backends.elasticsearch7` (Elasticsearch 7.x)
``wagtail.search.backends.elasticsearch6`` (Elasticsearch 6.x)
``wagtail.search.backends.elasticsearch7`` (Elasticsearch 7.x)
Prerequisites are the `Elasticsearch`_ service itself and, via pip, the `elasticsearch-py`_ package. The major version of the package must match the installed version of Elasticsearch:
.. _Elasticsearch: https://www.elastic.co/downloads/elasticsearch
.. code-block:: sh
Prerequisites are the [Elasticsearch](https://www.elastic.co/downloads/elasticsearch) service itself and, via pip, the [elasticsearch-py](https://elasticsearch-py.readthedocs.org) package. The major version of the package must match the installed version of Elasticsearch:
```sh
pip install "elasticsearch>=5.0.0,<6.0.0" # for Elasticsearch 5.x
```
.. code-block:: sh
```sh
pip install "elasticsearch>=6.4.0,<7.0.0" # for Elasticsearch 6.x
```
.. code-block:: sh
```sh
pip install "elasticsearch>=7.0.0,<8.0.0" # for Elasticsearch 7.x
```
.. warning::
| Version 6.3.1 of the Elasticsearch client library is incompatible with Wagtail. Use 6.4.0 or above.
```{warning}
Version 6.3.1 of the Elasticsearch client library is incompatible with Wagtail. Use 6.4.0 or above.
```
The backend is configured in settings:
.. code-block:: python
```python
WAGTAILSEARCH_BACKENDS = {
'default': {
'BACKEND': 'wagtail.search.backends.elasticsearch5',
@ -119,13 +103,13 @@ The backend is configured in settings:
'INDEX_SETTINGS': {},
}
}
```
Other than ``BACKEND``, the keys are optional and default to the values shown. Any defined key in ``OPTIONS`` is passed directly to the Elasticsearch constructor as case-sensitive keyword argument (e.g. ``'max_retries': 1``).
Other than `BACKEND`, the keys are optional and default to the values shown. Any defined key in `OPTIONS` is passed directly to the Elasticsearch constructor as case-sensitive keyword argument (e.g. `'max_retries': 1`).
A username and password may be optionally be supplied to the ``URL`` field to provide authentication credentials for the Elasticsearch service:
.. code-block:: python
A username and password may be optionally be supplied to the `URL` field to provide authentication credentials for the Elasticsearch service:
```python
WAGTAILSEARCH_BACKENDS = {
'default': {
...
@ -133,11 +117,11 @@ A username and password may be optionally be supplied to the ``URL`` field to pr
...
}
}
```
``INDEX_SETTINGS`` is a dictionary used to override the default settings to create the index. The default settings are defined inside the ``ElasticsearchSearchBackend`` class in the module ``wagtail/wagtail/search/backends/elasticsearch7.py``. Any new key is added, any existing key, if not a dictionary, is replaced with the new value. Here's a sample on how to configure the number of shards and setting the Italian LanguageAnalyzer as the default analyzer:
.. code-block:: python
`INDEX_SETTINGS` is a dictionary used to override the default settings to create the index. The default settings are defined inside the `ElasticsearchSearchBackend` class in the module `wagtail/wagtail/search/backends/elasticsearch7.py`. Any new key is added, any existing key, if not a dictionary, is replaced with the new value. Here's a sample on how to configure the number of shards and setting the Italian LanguageAnalyzer as the default analyzer:
```python
WAGTAILSEARCH_BACKENDS = {
'default': {
...,
@ -156,24 +140,20 @@ A username and password may be optionally be supplied to the ``URL`` field to pr
}
}
}
```
If you prefer not to run an Elasticsearch server in development or production, there are many hosted services available, including `Bonsai`_, who offer a free account suitable for testing and development. To use Bonsai:
If you prefer not to run an Elasticsearch server in development or production, there are many hosted services available, including [Bonsai](https://bonsai.io/), who offer a free account suitable for testing and development. To use Bonsai:
- Sign up for an account at `Bonsai`_
- Sign up for an account at `Bonsai`
- Use your Bonsai dashboard to create a Cluster.
- Configure ``URLS`` in the Elasticsearch entry in ``WAGTAILSEARCH_BACKENDS`` using the Cluster URL from your Bonsai dashboard
- Run ``./manage.py update_index``
- Configure `URLS` in the Elasticsearch entry in `WAGTAILSEARCH_BACKENDS` using the Cluster URL from your Bonsai dashboard
- Run `./manage.py update_index`
.. _elasticsearch-py: https://elasticsearch-py.readthedocs.org
.. _Bonsai: https://bonsai.io/
### Amazon AWS Elasticsearch
Amazon AWS Elasticsearch
~~~~~~~~~~~~~~~~~~~~~~~~
The Elasticsearch backend is compatible with `Amazon Elasticsearch Service`_, but requires additional configuration to handle IAM based authentication. This can be done with the `requests-aws4auth`_ package along with the following configuration:
.. code-block:: python
The Elasticsearch backend is compatible with [Amazon Elasticsearch Service](https://aws.amazon.com/elasticsearch-service/), but requires additional configuration to handle IAM based authentication. This can be done with the [requests-aws4auth](https://pypi.python.org/pypi/requests-aws4auth) package along with the following configuration:
```python
from elasticsearch import RequestsHttpConnection
from requests_aws4auth import AWS4Auth
@ -194,12 +174,8 @@ The Elasticsearch backend is compatible with `Amazon Elasticsearch Service`_, bu
},
}
}
```
.. _Amazon Elasticsearch Service: https://aws.amazon.com/elasticsearch-service/
.. _requests-aws4auth: https://pypi.python.org/pypi/requests-aws4auth
## Rolling Your Own
Rolling Your Own
----------------
Wagtail search backends implement the interface defined in ``wagtail/wagtail/wagtailsearch/backends/base.py``. At a minimum, the backend's ``search()`` method must return a collection of objects or ``model.objects.none()``. For a fully-featured search backend, examine the Elasticsearch backend code in ``elasticsearch.py``.
Wagtail search backends implement the interface defined in `wagtail/wagtail/wagtailsearch/backends/base.py`. At a minimum, the backend's `search()` method must return a collection of objects or `model.objects.none()`. For a fully-featured search backend, examine the Elasticsearch backend code in `elasticsearch.py`.

Wyświetl plik

@ -1,43 +1,36 @@
(wagtailsearch)=
.. _wagtailsearch:
======
Search
======
# Search
Wagtail provides a comprehensive and extensible search interface. In addition, it provides ways to promote search results through "Editor's Picks". Wagtail also collects simple statistics on queries made through the search interface.
.. toctree::
:maxdepth: 2
```{toctree}
---
maxdepth: 2
---
indexing
searching
backends
```
Indexing
========
## Indexing
To make objects searchable, they must first be added to the search index. This involves configuring the models and fields that you would like to index (which is done for you for Pages, Images and Documents), and then actually inserting them into the index.
See :ref:`wagtailsearch_indexing_update` for information on how to keep the objects in your search index in sync with the objects in your database.
See [](wagtailsearch_indexing_update) for information on how to keep the objects in your search index in sync with the objects in your database.
If you have created some extra fields in a subclass of ``Page`` or ``Image``, you may want to add these new fields to the search index, so a user's search query can match the Page or Image's extra content. See :ref:`wagtailsearch_indexing_fields`.
If you have created some extra fields in a subclass of `Page` or `Image`, you may want to add these new fields to the search index, so a user's search query can match the Page or Image's extra content. See [](wagtailsearch_indexing_fields).
If you have a custom model which doesn't derive from ``Page`` or ``Image`` that you would like to make searchable, see :ref:`wagtailsearch_indexing_models`.
If you have a custom model which doesn't derive from `Page` or `Image` that you would like to make searchable, see [](wagtailsearch_indexing_models).
Searching
=========
## Searching
Wagtail provides an API for performing search queries on your models. You can also perform search queries on Django QuerySets.
See :ref:`wagtailsearch_searching`.
See [](wagtailsearch_searching).
Backends
========
## Backends
Wagtail provides two backends for storing the search index and performing search queries: one using the database's full-text search capabilities, and another using Elasticsearch. It's also possible to roll your own search backend.
See :ref:`wagtailsearch_backends`
See [](wagtailsearch_backends).

Wyświetl plik

@ -1,88 +1,67 @@
(wagtailsearch_searching)=
.. _wagtailsearch_searching:
# Searching
(wagtailsearch_searching_pages)=
=========
Searching
=========
## Searching QuerySets
Wagtail search is built on Django's [QuerySet API](django:ref/models/querysets). You should be able to search any Django QuerySet provided the model and the fields being filtered on have been added to the search index.
.. _wagtailsearch_searching_pages:
### Searching Pages
Searching QuerySets
===================
Wagtail search is built on Django's `QuerySet API <https://docs.djangoproject.com/en/stable/ref/models/querysets/>`_. You should be able to search any Django QuerySet provided the model and the fields being filtered on have been added to the search index.
Searching Pages
---------------
Wagtail provides a shortcut for searching pages: the ``.search()`` ``QuerySet`` method. You can call this on any ``PageQuerySet``. For example:
.. code-block:: python
Wagtail provides a shortcut for searching pages: the `.search()` `QuerySet` method. You can call this on any `PageQuerySet`. For example:
```python
# Search future EventPages
>>> from wagtail.models import EventPage
>>> EventPage.objects.filter(date__gt=timezone.now()).search("Hello world!")
```
All other methods of `PageQuerySet` can be used with `search()`. For example:
All other methods of ``PageQuerySet`` can be used with ``search()``. For example:
.. code-block:: python
```python
# 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>]
```
```{note}
The `search()` method will convert your `QuerySet` into an instance of one of Wagtail's `SearchResults` classes (depending on backend). This means that you must perform filtering before calling `search()`.
```
.. note::
Before the `autocomplete()` method was introduced, the search method also did partial matching. This behaviour is will be deprecated and you should either switch to the new `autocomplete()` method or pass `partial_match=False` into the search method to opt-in to the new behaviour.
The partial matching in `search()` will be completely removed in a future release.
The ``search()`` method will convert your ``QuerySet`` into an instance of one of Wagtail's ``SearchResults`` classes (depending on backend). This means that you must perform filtering before calling ``search()``.
.. note::
Before the ``autocomplete()`` method was introduced, the search method also did partial matching. This behaviour is will be deprecated and you should
either switch to the new ``autocomplete()`` method or pass ``partial_match=False`` into the search method to opt-in to the new behaviour. The
partial matching in ``search()`` will be completely removed in a future release.
Autocomplete searches
---------------------
### Autocomplete searches
Wagtail provides a separate method which performs partial matching on specific autocomplete fields. This is useful for suggesting pages to the user in real-time as they type their query.
.. code-block:: python
```python
>>> EventPage.objects.live().autocomplete("Eve")
[<EventPage: Event 1>, <EventPage: Event 2>]
```
```{note}
This method should only be used for real-time autocomplete and actual search requests should always use the `search()` method.
```
.. tip::
(wagtailsearch_images_documents_custom_models)=
This method should only be used for real-time autocomplete and actual search requests should always use the ``search()`` method.
### Searching Images, Documents and custom models
Wagtail's document and image models provide a `search` method on their QuerySets, just as pages do:
.. _wagtailsearch_images_documents_custom_models:
Searching Images, Documents and custom models
---------------------------------------------
Wagtail's document and image models provide a ``search`` method on their QuerySets, just as pages do:
.. code-block:: python
```python
>>> from wagtail.images.models import Image
>>> Image.objects.filter(uploaded_by_user=user).search("Hello")
[<Image: Hello>, <Image: Hello world!>]
```
[Custom models](wagtailsearch_indexing_models) can be searched by using the `search` method on the search backend directly:
:ref:`Custom models <wagtailsearch_indexing_models>` can be searched by using the ``search`` method on the search backend directly:
.. code-block:: python
```python
>>> from myapp.models import Book
>>> from wagtail.search.backends import get_search_backend
@ -90,12 +69,11 @@ Wagtail's document and image models provide a ``search`` method on their QuerySe
>>> s = get_search_backend()
>>> s.search("Great", Book)
[<Book: Great Expectations>, <Book: The Great Gatsby>]
```
You can also pass a QuerySet into the `search` method which allows you to add filters to your search results:
You can also pass a QuerySet into the ``search`` method which allows you to add filters to your search results:
.. code-block:: python
```python
>>> from myapp.models import Book
>>> from wagtail.search.backends import get_search_backend
@ -103,41 +81,37 @@ You can also pass a QuerySet into the ``search`` method which allows you to add
>>> s = get_search_backend()
>>> s.search("Great", Book.objects.filter(published_date__year__lt=1900))
[<Book: Great Expectations>]
```
(wagtailsearch_specifying_fields)=
.. _wagtailsearch_specifying_fields:
### Specifying the fields to search
Specifying the fields to search
-------------------------------
By default, Wagtail will search all fields that have been indexed using `index.SearchField`.
By default, Wagtail will search all fields that have been indexed using ``index.SearchField``.
This can be limited to a certain set of fields by using the ``fields`` keyword argument:
.. code-block:: python
This can be limited to a certain set of fields by using the `fields` keyword argument:
```python
# Search just the title field
>>> EventPage.objects.search("Event", fields=["title"])
[<EventPage: Event 1>, <EventPage: Event 2>]
```
(wagtailsearch_faceted_search)=
.. _wagtailsearch_faceted_search:
Faceted search
--------------
### Faceted search
Wagtail supports faceted search which is a kind of filtering based on a taxonomy
field (such as category or page type).
The ``.facet(field_name)`` method returns an ``OrderedDict``. The keys are
The `.facet(field_name)` method returns an `OrderedDict`. The keys are
the IDs of the related objects that have been referenced by the specified field, and the
values are the number of references found for each ID. The results are ordered by number
of references descending.
For example, to find the most common page types in the search results:
.. code-block:: python
```python
>>> Page.objects.search("Test").facet("content_type_id")
# Note: The keys correspond to the ID of a ContentType object; the values are the
@ -146,12 +120,11 @@ For example, to find the most common page types in the search results:
('2', 4), # 4 pages have content_type_id == 2
('1', 2), # 2 pages have content_type_id == 1
])
```
Changing search behaviour
-------------------------
## Changing search behaviour
Search operator
^^^^^^^^^^^^^^^
### Search operator
The search operator specifies how search should behave when the user has typed in multiple search terms. There are two possible values:
@ -162,10 +135,9 @@ Both operators have benefits and drawbacks. The "or" operator will return many m
We recommend using the "or" operator when ordering by relevance and the "and" operator when ordering by anything else (note: the database backend doesn't currently support ordering by relevance).
Here's an example of using the ``operator`` keyword argument:
.. code-block:: python
Here's an example of using the `operator` keyword argument:
```python
# The database contains a "Thing" model with the following items:
# - Hello world
# - Hello
@ -186,26 +158,25 @@ Here's an example of using the ``operator`` keyword argument:
# Only "hello world" returned as that's the only item that contains both terms
[<Thing: Hello world>]
```
For page, image and document models, the ``operator`` keyword argument is also supported on the QuerySet's ``search`` method:
.. code-block:: python
For page, image and document models, the `operator` keyword argument is also supported on the QuerySet's `search` method:
```python
>>> Page.objects.search("Hello world", operator="or")
# All pages containing either "hello" or "world" are returned
[<Page: Hello World>, <Page: Hello>, <Page: World>]
```
Phrase searching
^^^^^^^^^^^^^^^^
### Phrase searching
Phrase searching is used for finding whole sentence or phrase rather than individual terms.
The terms must appear together and in the same order.
For example:
.. code-block:: python
```python
>>> from wagtail.search.query import Phrase
>>> Page.objects.search(Phrase("Hello world"))
@ -213,42 +184,42 @@ For example:
>>> Page.objects.search(Phrase("World hello"))
[<Page: World Hello day>]
```
If you are looking to implement phrase queries using the double-quote syntax, see :ref:`wagtailsearch_query_string_parsing`.
If you are looking to implement phrase queries using the double-quote syntax, see [](wagtailsearch_query_string_parsing).
.. _fuzzy_matching:
(fuzzy_matching)=
Fuzzy matching
^^^^^^^^^^^^^^
### Fuzzy matching
.. versionadded:: 4.0
```{versionadded} 4.0
Fuzzy matching will return documents which contain terms similar to the search term, as measured by a `Levenshtein edit distance <https://en.wikipedia.org/wiki/Levenshtein_distance>`.
```
Fuzzy matching will return documents which contain terms similar to the search term, as measured by a [Levenshtein edit distance](https://en.wikipedia.org/wiki/Levenshtein_distance).
A maximum of one edit (transposition, insertion, or removal of a character) is permitted for three to five letter terms, two edits for longer terms, and shorter terms must match exactly.
For example:
.. code-block:: python
```python
>>> from wagtail.search.query import Fuzzy
>>> Page.objects.search(Fuzzy("Hallo"))
[<Page: Hello World>]
```
Fuzzy matching is supported by the Elasticsearch search backend only.
(wagtailsearch_complex_queries)=
.. _wagtailsearch_complex_queries:
Complex search queries
^^^^^^^^^^^^^^^^^^^^^^
### Complex search queries
Through the use of search query classes, Wagtail also supports building search queries as Python
objects which can be wrapped by and combined with other search queries. The following classes are
available:
``PlainText(query_string, operator=None, boost=1.0)``
`PlainText(query_string, operator=None, boost=1.0)`
This class wraps a string of separate terms. This is the same as searching without query classes.
@ -256,56 +227,54 @@ It takes a query string, operator and boost.
For example:
.. code-block:: python
```python
>>> 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)``
`Phrase(query_string)`
This class wraps a string containing a phrase. See previous section for how this works.
For example:
.. code-block:: python
```python
# This example will match both the phrases "hello world" and "Hello earth"
>>> Page.objects.search(Phrase("Hello world") | Phrase("Hello earth"))
```
``Boost(query, boost)``
`Boost(query, boost)`
This class boosts the score of another query.
For example:
.. code-block:: python
```python
>>> 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"))
```
Note that this isn't supported by the PostgreSQL or database search backends.
.. _wagtailsearch_query_string_parsing:
(wagtailsearch_query_string_parsing)=
Query string parsing
^^^^^^^^^^^^^^^^^^^^
### Query string parsing
The previous sections show how to construct a phrase search query manually, but a lot of search engines (Wagtail admin included, try it!)
support writing phrase queries by wrapping the phrase with double-quotes. In addition to phrases, you might also want to allow users to
add filters into the query using the colon syntax (``hello world published:yes``).
add filters into the query using the colon syntax (`hello world published:yes`).
These two features can be implemented using the ``parse_query_string`` utility function. This function takes a query string that a user
These two features can be implemented using the `parse_query_string` utility function. This function takes a query string that a user
typed and returns a query object and dictionary of filters:
For example:
.. code-block:: python
```python
>>> 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')
@ -319,11 +288,11 @@ For example:
PlainText("my query string", operator='and'),
Phrase("this is a phrase"),
])
```
Here's an example of how this function can be used in a search view:
.. code-block:: python
```python
from wagtail.search.utils import parse_query_string
def search(request):
@ -345,27 +314,25 @@ Here's an example of how this function can be used in a search view:
pages = pages.search(query)
return render(request, 'search_results.html', {'pages': pages})
```
Custom ordering
^^^^^^^^^^^^^^^
### Custom ordering
By default, search results are ordered by relevance, if the backend supports it. To preserve the QuerySet's existing ordering, the ``order_by_relevance`` keyword argument needs to be set to ``False`` on the ``search()`` method.
By default, search results are ordered by relevance, if the backend supports it. To preserve the QuerySet's existing ordering, the `order_by_relevance` keyword argument needs to be set to `False` on the `search()` method.
For example:
.. code-block:: python
```python
# 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>]
```
(wagtailsearch_annotating_results_with_score)=
.. _wagtailsearch_annotating_results_with_score:
Annotating results with score
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
### Annotating results with score
For each matched result, Elasticsearch calculates a "score", which is a number
that represents how relevant the result is based on the user's query. The
@ -373,13 +340,12 @@ results are usually ordered based on the score.
There are some cases where having access to the score is useful (such as
programmatically combining two queries for different models). You can add the
score to each result by calling the ``.annotate_score(field)`` method on the
``SearchQuerySet``.
score to each result by calling the `.annotate_score(field)` method on the
`SearchQuerySet`.
For example:
.. code-block:: python
```python
>>> events = EventPage.objects.search("Event").annotate_score("_score")
>>> for event in events:
... print(event.title, event._score)
@ -387,19 +353,18 @@ For example:
("Easter", 2.5),
("Halloween", 1.7),
("Christmas", 1.5),
```
Note that the score itself is arbitrary and it is only useful for comparison
of results for the same query.
.. _wagtailsearch_frontend_views:
(wagtailsearch_frontend_views)=
An example page search view
===========================
## An example page search view
Here's an example Django view that could be used to add a "search" page to your site:
.. code-block:: python
```python
# views.py
from django.shortcuts import render
@ -424,12 +389,11 @@ Here's an example Django view that could be used to add a "search" page to your
'search_query': search_query,
'search_results': search_results,
})
```
And here's a template to go with it:
.. code-block:: html+django
```html+django
{% extends "base.html" %}
{% load wagtailcore_tags %}
@ -458,11 +422,10 @@ And here's a template to go with it:
Please type something into the search box
{% endif %}
{% endblock %}
```
Promoted search results
=======================
## Promoted search results
"Promoted search results" allow editors to explicitly link relevant content to search terms, so results pages can contain curated content in addition to results from the search engine.
This functionality is provided by the :mod:`~wagtail.contrib.search_promotions` contrib module.
This functionality is provided by the {mod}`~wagtail.contrib.search_promotions` contrib module.