Как поддерживать индекс Elasticsearch в актуальном состоянии, используя asticsearch-dsl-py?

Я разработал небольшой каталог личной информации, который мой клиент получает и обновляет через интерфейс администратора Django. Эта информация должна быть доступна для поиска, поэтому я настроил свой сайт Django, чтобы сохранить эти данные в поисковом индексе. Первоначально я использовал Haystack и Whoosh для поискового индекса, но недавно мне пришлось отказаться от этих инструментов и переключиться на Elasticsearch 5.

Ранее всякий раз, когда что-либо в каталоге обновлялось, код просто очищал весь поисковый индекс и перестраивал его с нуля. В этом каталоге всего несколько сотен записей, так что это не было неэффективным. К сожалению, попытки сделать то же самое в Elasticsearch очень ненадежны из-за того, что я предполагаю, что в моем коде есть какое-то условие гонки.

Вот код, который я написал, который использует asticsearch-py и asticsearch-dsl-py:

import elasticsearch
import time
from django.apps import apps
from django.conf import settings
from elasticsearch.helpers import bulk
from elasticsearch_dsl.connections import connections
from elasticsearch_dsl import DocType, Text, Search

# Create the default Elasticsearch connection using the host specified in settings.py.
elasticsearch_host = "{0}:{1}".format(
    settings.ELASTICSEARCH_HOST['HOST'], settings.ELASTICSEARCH_HOST['PORT']
)
elasticsearch_connection = connections.create_connection(hosts=[elasticsearch_host])


class DepartmentIndex(DocType):
    url = Text()
    name = Text()
    text = Text(analyzer='english')
    content_type = Text()

    class Meta:
        index = 'departmental_directory'


def refresh_index():
    # Erase the existing index.
    try:
        elasticsearch_connection.indices.delete(index=DepartmentIndex().meta.index)
    except elasticsearch.exceptions.NotFoundError:
        # If it doesn't exist, the job's already done.
        pass

    # Wait a few seconds to give enough time for Elasticsearch to accept that the 
    # DepartmentIndex is gone before we try to recreate it.
    time.sleep(3)

    # Rebuild the index from scratch.
    DepartmentIndex.init()
    Department = apps.get_model('departmental_directory', 'Department')
    bulk(
        client=elasticsearch_connection, 
        actions=(b.indexing() for b in Department.objects.all().iterator())
    )

Я настроил сигналы Джанго для вызова refresh_index() всякий раз, когда Department получил спасение. Но refresh_index() часто сбой из-за этой ошибки:

elasticsearch.exceptions.RequestError: TransportError(400, u'index_already_exists_exception', u'index [departmental_directory/uOQdBukEQBWvMZk83eByug] already exists')

Вот почему я добавил, что time.sleep(3) вызов. Я предполагаю, что индекс не был полностью удален к тому времени DepartmentIndex.init() называется, который был причиной ошибки.

Я предполагаю, что я просто поступил об этом совершенно неправильно. Должен быть лучший способ поддерживать индекс эластичного поиска в актуальном состоянии, используя asticsearch-dsl-py, но я просто не знаю, что это такое, и я не смог выяснить это через их документы.

Поиск по запросу "Перестроить индекс эластичного поиска с нуля" в Google дает множество результатов для "Как переиндексировать данные эластичного поиска", но это не то, что мне нужно. Мне нужно заменить данные новыми, более свежими данными из базы данных моего приложения.

1 ответ

Решение

Может быть, это поможет: https://github.com/HonzaKral/es-django-example/blob/master/qa/models.py

В любом случае вы хотите использовать два метода: пакетную загрузку всех ваших данных в новый индекс ( https://github.com/HonzaKral/es-django-example/blob/master/qa/management/commands/index_data.py) и, необязательно, синхронизацию с использованием способов / или сигналов, как упомянуто выше.

Другие вопросы по тегам