Elasticsearch 2 support (#2573)

* Created Elasticsearch 2 backend

* Added tests for Elasticsearch 2 backend

* Split models up into different indices

pages, images and documents are now in separate indices

* Prefix fields of child models to prevent mapping clashes

* Replaced index_analyzer with analyzer/search_analyzer

index_analyzer has been removed in Elasticsearch 2.0

https://www.elastic.co/guide/en/elasticsearch/reference/current/breaking_20_mapping_changes.html#_analyzer_mappings

There's no indication in Elasticsearch's docs that this wouldn't work on Elasticsearch 1.x. However, we found that the new configuration isn't reliable on Elasticsearch 1.6 and below (causes the test_query_analyzer test to fail randomly).

* Implemented new way of representing content types in search index

Instead of using a long string of model names that is queried using a
"prefix" query, we instead use a multi-value string field and query it
using a simple "match" query.

The only reason why this isn't implemented in the Elasticsearch 1.x
backend yet is backwards compatibility

* Added another child model of SearchTest with clashing field mapping

This checks that the namespacing of fields on child models is working properly (if it doesn't the update_index tests will fail)

* Added tests for get_model_root function

* fixup! Added tests for get_model_root function

* Docs updates for Elasticsearch 2 support

Also tweak examples to use elasticsearch2 backend by default

* Test against Elasticsearch 2 on travis
pull/2966/head
Karl Hobley 2016-05-06 11:23:31 +01:00 zatwierdzone przez Mikalai Radchuk
rodzic 68d19d1efb
commit daa82936d7
15 zmienionych plików z 1421 dodań i 43 usunięć

Wyświetl plik

@ -32,6 +32,15 @@ matrix:
python: 2.7
- env: TOXENV=py34-dj19-sqlite-elasticsearch
python: 3.5
- env: TOXENV=py27-dj18-sqlite-elasticsearch2 INSTALL_ELASTICSEARCH2=yes
python: 2.7
sudo: true
- env: TOXENV=py27-dj19-postgres-elasticsearch2 INSTALL_ELASTICSEARCH2=yes
python: 2.7
sudo: true
- env: TOXENV=py34-dj19-sqlite-elasticsearch2 INSTALL_ELASTICSEARCH2=yes
python: 3.5
sudo: true
- env: TOXENV=py27-dj110-sqlite-noelasticsearch
python: 2.7
- env: TOXENV=py27-dj110-postgres-noelasticsearch
@ -40,6 +49,9 @@ matrix:
python: 2.7
- env: TOXENV=py27-dj110-mysql-elasticsearch
python: 2.7
- env: TOXENV=py27-dj110-mysql-elasticsearch2 INSTALL_ELASTICSEARCH2=yes
python: 2.7
sudo: true
- env: TOXENV=py34-dj110-postgres-noelasticsearch
python: 3.4
- env: TOXENV=py34-dj110-sqlite-noelasticsearch
@ -54,12 +66,21 @@ matrix:
python: 3.5
- env: TOXENV=py35-dj110-postgres-elasticsearch
python: 3.5
- env: TOXENV=py35-dj110-postgres-elasticsearch2 INSTALL_ELASTICSEARCH2=yes
python: 3.5
sudo: true
allow_failures:
- env: TOXENV=py27-dj18-sqlite-elasticsearch
- env: TOXENV=py27-dj19-postgres-elasticsearch
- env: TOXENV=py34-dj19-sqlite-elasticsearch
- env: TOXENV=py27-dj110-mysql-elasticsearch
- env: TOXENV=py35-dj110-postgres-elasticsearch
- env: TOXENV=py27-dj18-sqlite-elasticsearch2 INSTALL_ELASTICSEARCH2=yes
- env: TOXENV=py27-dj19-postgres-elasticsearch2 INSTALL_ELASTICSEARCH2=yes
- env: TOXENV=py34-dj19-sqlite-elasticsearch2 INSTALL_ELASTICSEARCH2=yes
- env: TOXENV=py27-dj110-mysql-elasticsearch2 INSTALL_ELASTICSEARCH2=yes
- env: TOXENV=py35-dj110-postgres-elasticsearch2 INSTALL_ELASTICSEARCH2=yes
# Services
services:
@ -68,6 +89,7 @@ services:
# Package installation
install:
- pip install tox coveralls
- 'if [[ -n "$INSTALL_ELASTICSEARCH2" ]]; then ./scripts/travis/install_elasticsearch2.sh; fi'
# Pre-test configuration
before_script:

Wyświetl plik

@ -185,7 +185,7 @@ Search
# Replace the search backend
WAGTAILSEARCH_BACKENDS = {
'default': {
'BACKEND': 'wagtail.wagtailsearch.backends.elasticsearch',
'BACKEND': 'wagtail.wagtailsearch.backends.elasticsearch2',
'INDEX': 'myapp'
}
}
@ -368,7 +368,7 @@ URL Patterns
urlpatterns = [
url(r'^django-admin/', include(admin.site.urls)),
url(r'^admin/', include(wagtailadmin_urls)),
url(r'^search/', include(wagtailsearch_urls)),
url(r'^documents/', include(wagtaildocs_urls)),
@ -578,7 +578,7 @@ These two files should reside in your project directory (``myproject/myproject/`
# Replace the search backend
#WAGTAILSEARCH_BACKENDS = {
# 'default': {
# 'BACKEND': 'wagtail.wagtailsearch.backends.elasticsearch',
# 'BACKEND': 'wagtail.wagtailsearch.backends.elasticsearch2',
# 'INDEX': 'myapp'
# }
#}

Wyświetl plik

@ -82,20 +82,22 @@ If any of these features are important to you, we recommend using Elasticsearch
Elasticsearch Backend
---------------------
``wagtail.wagtailsearch.backends.elasticsearch``
``wagtail.wagtailsearch.backends.elasticsearch`` (Elasticsearch 1.x)
``wagtail.wagtailsearch.backends.elasticsearch2`` (Elasticsearch 2.x)
.. versionchanged:: 1.1
Before 1.1, the full path to the backend class had to be specified: ``wagtail.wagtailsearch.backends.elasticsearch.ElasticSearch``
.. versionchanged:: 1.7
Support for Elasticsearch 2.x was added
Prerequisites are the `Elasticsearch`_ service itself and, via pip, the `elasticsearch-py`_ package:
.. _Elasticsearch: https://www.elastic.co/downloads/past-releases/elasticsearch-1-7-3
.. note::
Wagtail doesn't support Elasticsearch 2.0 yet; please use 1.x in the meantime. Elasticsearch 2.0 support is scheduled for a future release.
.. code-block:: sh
pip install elasticsearch
@ -106,7 +108,7 @@ The backend is configured in settings:
WAGTAILSEARCH_BACKENDS = {
'default': {
'BACKEND': 'wagtail.wagtailsearch.backends.elasticsearch',
'BACKEND': 'wagtail.wagtailsearch.backends.elasticsearch2',
'URLS': ['http://localhost:9200'],
'INDEX': 'wagtail',
'TIMEOUT': 5,

Wyświetl plik

@ -17,6 +17,7 @@ def make_parser():
parser.add_argument('--deprecation', choices=['all', 'pending', 'imminent', 'none'], default='pending')
parser.add_argument('--postgres', action='store_true')
parser.add_argument('--elasticsearch', action='store_true')
parser.add_argument('--elasticsearch2', action='store_true')
parser.add_argument('rest', nargs='*')
return parser
@ -49,6 +50,13 @@ def runtests():
if args.elasticsearch:
os.environ.setdefault('ELASTICSEARCH_URL', 'http://localhost:9200')
os.environ.setdefault('ELASTICSEARCH_VERSION', '1')
if args.elasticsearch2:
raise RuntimeError("You cannot test both Elasticsearch 1 and 2 together")
elif args.elasticsearch2:
os.environ.setdefault('ELASTICSEARCH_URL', 'http://localhost:9200')
os.environ.setdefault('ELASTICSEARCH_VERSION', '2')
elif 'ELASTICSEARCH_URL' in os.environ:
# forcibly delete the ELASTICSEARCH_URL setting to skip those tests
del os.environ['ELASTICSEARCH_URL']

Wyświetl plik

@ -0,0 +1,7 @@
#!/bin/bash
sudo apt-get autoremove --purge elasticsearch
wget -qO - https://packages.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
echo "deb http://packages.elastic.co/elasticsearch/2.x/debian stable main" | sudo tee -a /etc/apt/sources.list.d/elk.list
sudo apt-get update && sudo apt-get install elasticsearch -y
sudo service elasticsearch start

Wyświetl plik

@ -2,14 +2,15 @@
skipsdist = True
usedevelop = True
envlist = py{27,33,34,35}-dj{18,19}-{sqlite,postgres,mysql}-{elasticsearch,noelasticsearch},
py{27,34,35}-dj110-{sqlite,postgres,mysql}-{elasticsearch,noelasticsearch},
envlist = py{27,33,34,35}-dj{18,19}-{sqlite,postgres,mysql}-{elasticsearch2,elasticsearch,noelasticsearch},
py{27,34,35}-dj110-{sqlite,postgres,mysql}-{elasticsearch2,elasticsearch,noelasticsearch},
flake8
[testenv]
install_command = pip install -e ".[testing]" -U {opts} {packages}
commands =
elasticsearch: coverage run runtests.py wagtail.wagtailsearch wagtail.wagtaildocs wagtail.wagtailimages --elasticsearch
elasticsearch2: coverage run runtests.py wagtail.wagtailsearch wagtail.wagtaildocs wagtail.wagtailimages --elasticsearch2
noelasticsearch: coverage run runtests.py
basepython =
@ -27,6 +28,7 @@ deps =
dj110: Django>=1.10a1,<1.11
postgres: psycopg2>=2.6
mysql: mysqlclient==1.3.6
elasticsearch2: elasticsearch>=2,<3
setenv =
postgres: DATABASE_ENGINE=django.db.backends.postgresql_psycopg2

Wyświetl plik

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10 on 2016-08-25 15:17
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('searchtests', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='AnotherSearchTestChild',
fields=[
('searchtest_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='searchtests.SearchTest')),
('subtitle', models.CharField(blank=True, max_length=255, null=True)),
],
bases=('searchtests.searchtest',),
),
]

Wyświetl plik

@ -69,3 +69,13 @@ class SearchTestChild(SearchTest):
index.FilterField('live'),
]),
]
class AnotherSearchTestChild(SearchTest):
# Checks that having the same field name in two child models with different
# search configuration doesn't give an error
subtitle = models.CharField(max_length=255, null=True, blank=True)
search_fields = SearchTest.search_fields + [
index.SearchField('subtitle', boost=10),
]

Wyświetl plik

@ -168,8 +168,13 @@ WAGTAILSEARCH_BACKENDS = {
AUTH_USER_MODEL = 'customuser.CustomUser'
if 'ELASTICSEARCH_URL' in os.environ:
if os.environ.get('ELASTICSEARCH_VERSION') == '2':
backend = 'wagtail.wagtailsearch.backends.elasticsearch2'
else:
backend = 'wagtail.wagtailsearch.backends.elasticsearch'
WAGTAILSEARCH_BACKENDS['elasticsearch'] = {
'BACKEND': 'wagtail.wagtailsearch.backends.elasticsearch',
'BACKEND': backend,
'URLS': [os.environ['ELASTICSEARCH_URL']],
'TIMEOUT': 10,
'max_retries': 1,

Wyświetl plik

@ -12,7 +12,8 @@ from elasticsearch.helpers import bulk
from wagtail.utils.deprecation import RemovedInWagtail18Warning
from wagtail.wagtailsearch.backends.base import (
BaseSearchBackend, BaseSearchQuery, BaseSearchResults)
from wagtail.wagtailsearch.index import FilterField, RelatedFields, SearchField, class_is_indexed
from wagtail.wagtailsearch.index import (
FilterField, Indexed, RelatedFields, SearchField, class_is_indexed)
class ElasticsearchMapping(object):
@ -42,9 +43,21 @@ class ElasticsearchMapping(object):
'TimeField': 'date',
}
# Contains the configuration required to use the edgengram_analyzer
# on a field. It's different in Elasticsearch 2 so it's been put in
# an attribute here to make it easier to override in a subclass.
edgengram_analyzer_config = {
'index_analyzer': 'edgengram_analyzer',
}
def __init__(self, model):
self.model = model
def get_parent(self):
for base in self.model.__bases__:
if issubclass(base, Indexed) and issubclass(base, models.Model):
return type(self)(base)
def get_document_type(self):
return self.model.indexed_get_content_type()
@ -75,7 +88,7 @@ class ElasticsearchMapping(object):
mapping['boost'] = field.boost
if field.partial_match:
mapping['index_analyzer'] = 'edgengram_analyzer'
mapping.update(self.edgengram_analyzer_config)
mapping['include_in_all'] = True
@ -94,8 +107,9 @@ class ElasticsearchMapping(object):
fields = {
'pk': dict(type='string', index='not_analyzed', store='yes', include_in_all=False),
'content_type': dict(type='string', index='not_analyzed', include_in_all=False),
'_partials': dict(type='string', index_analyzer='edgengram_analyzer', include_in_all=False),
'_partials': dict(type='string', include_in_all=False),
}
fields['_partials'].update(self.edgengram_analyzer_config)
fields.update(dict(
self.get_field_mapping(field) for field in self.model.get_search_fields()
@ -305,15 +319,18 @@ class ElasticsearchSearchQuery(BaseSearchQuery):
return query
def get_content_type_filter(self):
return {
'prefix': {
'content_type': self.queryset.model.indexed_get_content_type()
}
}
def get_filters(self):
filters = []
# Filter by content type
filters.append({
'prefix': {
'content_type': self.queryset.model.indexed_get_content_type()
}
})
filters.append(self.get_content_type_filter())
# Apply filters from queryset
queryset_filters = self._get_filters_from_queryset()

Wyświetl plik

@ -0,0 +1,143 @@
from __future__ import absolute_import, unicode_literals
from wagtail.wagtailsearch.index import FilterField, RelatedFields, SearchField
from .elasticsearch import (
ElasticsearchIndex, ElasticsearchMapping, ElasticsearchSearchBackend, ElasticsearchSearchQuery,
ElasticsearchSearchResults)
def get_model_root(model):
"""
This function finds the root model for any given model. The root model is
the highest concrete model that it descends from. If the model doesn't
descend from another concrete model then the model is it's own root model so
it is returned.
Examples:
>>> get_model_root(wagtailcore.Page)
wagtailcore.Page
>>> get_model_root(myapp.HomePage)
wagtailcore.Page
>>> get_model_root(wagtailimages.Image)
wagtailimages.Image
"""
if model._meta.parents:
parent_model = list(model._meta.parents.items())[0][0]
return get_model_root(parent_model)
return model
class Elasticsearch2Mapping(ElasticsearchMapping):
edgengram_analyzer_config = {
'analyzer': 'edgengram_analyzer',
'search_analyzer': 'standard',
}
def get_field_column_name(self, field):
# Fields in derived models get prefixed with their model name, fields
# in the root model don't get prefixed at all
# This is to prevent mapping clashes in cases where two page types have
# a field with the same name but a different type.
root_model = get_model_root(self.model)
definition_model = field.get_definition_model(self.model)
if definition_model != root_model:
prefix = definition_model._meta.app_label.lower() + '_' + definition_model.__name__.lower() + '__'
else:
prefix = ''
if isinstance(field, FilterField):
return prefix + field.get_attname(self.model) + '_filter'
elif isinstance(field, SearchField):
return prefix + field.get_attname(self.model)
elif isinstance(field, RelatedFields):
return prefix + field.field_name
def get_content_type(self):
"""
Returns the content type as a string for the model.
For example: "wagtailcore.Page"
"myapp.MyModel"
"""
return self.model._meta.app_label + '.' + self.model.__name__
def get_all_content_types(self):
"""
Returns all the content type strings that apply to this model.
This includes the models' content type and all concrete ancestor
models that inherit from Indexed.
For example: ["myapp.MyPageModel", "wagtailcore.Page"]
["myapp.MyModel"]
"""
# Add our content type
content_types = [self.get_content_type()]
# Add all ancestor classes content types as well
ancestor = self.get_parent()
while ancestor:
content_types.append(ancestor.get_content_type())
ancestor = ancestor.get_parent()
return content_types
def get_document(self, obj):
# In the Elasticsearch 2 backend, we use a more efficient way to
# represent the content type of a document.
# Instead of using a long string of model names that is queried using a
# "prefix" query, we instead use a multi-value string field and query it
# using a simple "match" query.
# The only reason why this isn't implemented in the Elasticsearch 1.x
# backend yet is backwards compatibility
doc = super(Elasticsearch2Mapping, self).get_document(obj)
doc['content_type'] = self.get_all_content_types()
return doc
class Elasticsearch2Index(ElasticsearchIndex):
pass
class Elasticsearch2SearchQuery(ElasticsearchSearchQuery):
mapping_class = Elasticsearch2Mapping
def get_content_type_filter(self):
# Query content_type using a "match" query. See comment in
# Elasticsearch2Mapping.get_document for more details
content_type = self.mapping_class(self.queryset.model).get_content_type()
return {
'match': {
'content_type': content_type
}
}
class Elasticsearch2SearchResults(ElasticsearchSearchResults):
pass
class Elasticsearch2SearchBackend(ElasticsearchSearchBackend):
mapping_class = Elasticsearch2Mapping
index_class = Elasticsearch2Index
query_class = Elasticsearch2SearchQuery
results_class = Elasticsearch2SearchResults
def get_index_for_model(self, model):
# Split models up into separate indices based on their root model.
# For example, all page-derived models get put together in one index,
# while images and documents each have their own index.
root_model = get_model_root(model)
index_suffix = '__' + root_model._meta.app_label.lower() + '_' + root_model.__name__.lower()
return self.index_class(self, self.index_name + index_suffix)
SearchBackend = Elasticsearch2SearchBackend

Wyświetl plik

@ -1,5 +1,6 @@
from __future__ import absolute_import, unicode_literals
import inspect
import logging
from django.apps import apps
@ -178,6 +179,16 @@ class BaseField(object):
except models.fields.FieldDoesNotExist:
return self.field_name
def get_definition_model(self, cls):
try:
field = self.get_field(cls)
return field.model
except models.fields.FieldDoesNotExist:
# Find where it was defined by walking the inheritance tree
for base_cls in inspect.getmro(cls):
if self.field_name in base_cls.__dict__:
return base_cls
def get_type(self, cls):
if 'type' in self.kwargs:
return self.kwargs['type']
@ -224,6 +235,10 @@ class RelatedFields(object):
def get_field(self, cls):
return cls._meta.get_field(self.field_name)
def get_definition_model(self, cls):
field = self.get_field(cls)
return field.model
def get_value(self, obj):
field = self.get_field(obj.__class__)

Wyświetl plik

@ -17,6 +17,7 @@ from wagtail.wagtailsearch.backends import (
InvalidSearchBackendError, get_search_backend, get_search_backends)
from wagtail.wagtailsearch.backends.base import FieldError
from wagtail.wagtailsearch.backends.db import DatabaseSearchBackend
from wagtail.wagtailsearch.management.commands.update_index import group_models_by_index
class BackendTests(WagtailTestUtils):
@ -35,11 +36,22 @@ class BackendTests(WagtailTestUtils):
self.load_test_data()
def reset_index(self):
if self.backend.rebuilder_class:
for index, indexed_models in group_models_by_index(self.backend, [models.SearchTest, models.SearchTestChild]).items():
rebuilder = self.backend.rebuilder_class(index)
index = rebuilder.start()
for model in indexed_models:
index.add_model(model)
rebuilder.finish()
def refresh_index(self):
index = self.backend.get_index_for_model(models.SearchTest)
if index:
index.refresh()
def load_test_data(self):
# Reset the index
self.backend.reset_index()
self.backend.add_type(models.SearchTest)
self.backend.add_type(models.SearchTestChild)
self.reset_index()
# Create a test database
testa = models.SearchTest()
@ -71,8 +83,7 @@ class BackendTests(WagtailTestUtils):
self.backend.add(testd)
self.testd = testd
# Refresh the index
self.backend.refresh_index()
self.refresh_index()
def test_blank_search(self):
results = self.backend.search("", models.SearchTest)
@ -148,14 +159,14 @@ class BackendTests(WagtailTestUtils):
# Delete one of the objects
self.backend.delete(self.testa)
self.testa.delete()
self.backend.refresh_index()
self.refresh_index()
results = self.backend.search(None, models.SearchTest)
self.assertEqual(set(results), {self.testb, self.testc.searchtest_ptr, self.testd.searchtest_ptr})
def test_update_index_command(self):
# Reset the index, this should clear out the index
self.backend.reset_index()
self.reset_index()
# Give Elasticsearch some time to catch up...
time.sleep(1)

Wyświetl plik

@ -50,7 +50,7 @@ class TestElasticsearchSearchBackend(BackendTests, TestCase):
def test_partial_search(self):
# Reset the index
self.backend.reset_index()
self.reset_index()
self.backend.add_type(models.SearchTest)
self.backend.add_type(models.SearchTestChild)
@ -62,7 +62,7 @@ class TestElasticsearchSearchBackend(BackendTests, TestCase):
self.backend.add(obj)
# Refresh the index
self.backend.refresh_index()
self.refresh_index()
# Search and check
results = self.backend.search("HelloW", models.SearchTest.objects.all())
@ -72,7 +72,7 @@ class TestElasticsearchSearchBackend(BackendTests, TestCase):
def test_child_partial_search(self):
# Reset the index
self.backend.reset_index()
self.reset_index()
self.backend.add_type(models.SearchTest)
self.backend.add_type(models.SearchTestChild)
@ -84,7 +84,7 @@ class TestElasticsearchSearchBackend(BackendTests, TestCase):
self.backend.add(obj)
# Refresh the index
self.backend.refresh_index()
self.refresh_index()
# Search and check
results = self.backend.search("HelloW", models.SearchTest.objects.all())
@ -94,7 +94,7 @@ class TestElasticsearchSearchBackend(BackendTests, TestCase):
def test_ascii_folding(self):
# Reset the index
self.backend.reset_index()
self.reset_index()
self.backend.add_type(models.SearchTest)
self.backend.add_type(models.SearchTestChild)
@ -106,7 +106,7 @@ class TestElasticsearchSearchBackend(BackendTests, TestCase):
self.backend.add(obj)
# Refresh the index
self.backend.refresh_index()
self.refresh_index()
# Search and check
results = self.backend.search("Hello", models.SearchTest.objects.all())
@ -120,7 +120,7 @@ class TestElasticsearchSearchBackend(BackendTests, TestCase):
have it also as their query analyser
"""
# Reset the index
self.backend.reset_index()
self.reset_index()
self.backend.add_type(models.SearchTest)
self.backend.add_type(models.SearchTestChild)
@ -132,7 +132,7 @@ class TestElasticsearchSearchBackend(BackendTests, TestCase):
self.backend.add(obj)
# Refresh the index
self.backend.refresh_index()
self.refresh_index()
# Test search for "Hello"
results = self.backend.search("Hello", models.SearchTest.objects.all())
@ -154,7 +154,7 @@ class TestElasticsearchSearchBackend(BackendTests, TestCase):
See: https://github.com/torchbox/wagtail/issues/937
"""
# Reset the index
self.backend.reset_index()
self.reset_index()
self.backend.add_type(models.SearchTest)
self.backend.add_type(models.SearchTestChild)
@ -166,7 +166,7 @@ class TestElasticsearchSearchBackend(BackendTests, TestCase):
self.backend.add(obj)
# Refresh the index
self.backend.refresh_index()
self.refresh_index()
# Test search for "Hello-World"
results = self.backend.search("Hello-World", models.SearchTest.objects.all())
@ -176,7 +176,7 @@ class TestElasticsearchSearchBackend(BackendTests, TestCase):
def test_custom_ordering(self):
# Reset the index
self.backend.reset_index()
self.reset_index()
self.backend.add_type(models.SearchTest)
# Add some test data
@ -196,7 +196,7 @@ class TestElasticsearchSearchBackend(BackendTests, TestCase):
self.backend.add(b)
# Refresh the index
self.backend.refresh_index()
self.refresh_index()
# Do a search ordered by relevence
results = self.backend.search("Hello", models.SearchTest.objects.all())
@ -212,7 +212,7 @@ class TestElasticsearchSearchBackend(BackendTests, TestCase):
# Testing for bug #1859
# Reset the index
self.backend.reset_index()
self.reset_index()
self.backend.add_type(models.SearchTest)
a = models.SearchTest()
@ -223,7 +223,7 @@ class TestElasticsearchSearchBackend(BackendTests, TestCase):
self.backend.add(a)
# Refresh the index
self.backend.refresh_index()
self.refresh_index()
# Run query with "and" operator and single field
results = self.backend.search("Hello World", models.SearchTest, operator='and', fields=['title'])
@ -231,7 +231,7 @@ class TestElasticsearchSearchBackend(BackendTests, TestCase):
def test_update_index_command_schema_only(self):
# Reset the index, this should clear out the index
self.backend.reset_index()
self.reset_index()
# Give Elasticsearch some time to catch up...
time.sleep(1)
@ -979,6 +979,7 @@ class TestBackendConfiguration(TestCase):
@unittest.skipUnless(os.environ.get('ELASTICSEARCH_URL', False), "ELASTICSEARCH_URL not set")
@unittest.skipUnless(os.environ.get('ELASTICSEARCH_VERSION', '1') == '1', "ELASTICSEARCH_VERSION not set to 1")
class TestRebuilder(TestCase):
def assertDictEqual(self, a, b):
default = JSONSerializer().default
@ -1025,6 +1026,7 @@ class TestRebuilder(TestCase):
@unittest.skipUnless(os.environ.get('ELASTICSEARCH_URL', False), "ELASTICSEARCH_URL not set")
@unittest.skipUnless(os.environ.get('ELASTICSEARCH_VERSION', '1') == '1', "ELASTICSEARCH_VERSION not set to 1")
class TestAtomicRebuilder(TestCase):
def setUp(self):
self.backend = get_search_backend('elasticsearch')