Индексирование Elasticsearch в Django Задаче Сельдерея - PullRequest
0 голосов
/ 18 апреля 2020

Я создаю веб-приложение Django для хранения документов и связанных с ними метаданных.

Большая часть метаданных будет храниться в базовой базе данных MySQL с текстом документа OCR. индексируется в Elasticsearch для включения полнотекстового поиска. Я включил django -elasticsearch-dsl для подключения и синхронизации своих моделей данных, так как я также индексирую (и, таким образом, дважды храню) несколько других полей, найденных в моих моделях. Я подумывал об использовании Haystack , но ему не хватает поддержки последних версий Elasticsearch.

Когда документ загружается через интерфейс администратора приложений, сигнал post_save автоматически вызывает Celery асинхронная фоновая задача для выполнения OCR и, в конечном итоге, индексирование извлеченного текста в Elasticsearch.

Видя, что в моей модели не определено полнотекстовое поле (и я надеюсь избежать этого, поскольку я не хочу сохранять или искать в базе данных CLOB), я ищу лучшую практику для обновления моих документов Elasticsearch из моего файла tasks.py. Кажется, не существует способа сделать это с помощью django -elasticseach-dsl (но, возможно, я ошибаюсь?), И поэтому мне интересно, должен ли я либо:

  1. Попробуйте установить интерфейс с Elasticsearch через REST, используя сестринский пакет django -elasticsearch-dsl-drf .

  2. Более свободно интегрировать мое приложение с Elasticsearch с помощью более ванильный пакет эластичный поиск-dsl-py (на основе эластичного поиска-py). Я бы потерял некоторую «роскошь» с этим подходом, поскольку мне пришлось бы написать немного больше кода интеграции, по крайней мере, если бы я хотел соединить свои модели с сигналами.

Is есть лучшая практика? Или другой подход, который я не рассмотрел?

Обновление 1: Пытаясь реализовать ответ от @Nielk, я могу сохранить текст распознавания (result = "test "в tasks.py ниже) в ElasticSearch, но он также сохраняется в базе данных MySQL. Я все еще не понимаю, как настроить Submission.rawtext как промежуточный элемент ElasticSearch.

models.py:

class Submission(models.Model):

  rawtext = models.TextField(null=True, blank=True)
  ...
  def type_to_string(self):
    return ""

documents.py :

@registry.register_document
class SubmissionDocument(Document)

  rawtext = fields.TextField(attr="type_to_string")

  def prepare_rawtext(self, instance):
    # self.rawtext = None
    # instance.rawtext = "test"

    return instance.rawtext

  ... 

tasks.py (вызывается по сигналу post_save модели отправки):

  @shared_task
  def process_ocr(my_uuid)

    result = "test" # will ultimately be OCR'd text

    instance = Submission.objects.get(my_uuid=my_uuid)
    instance.rawtext = result
    instance.save()

Обновление 2 (рабочий раствор):

models.py Класс Представление (models.Model):

   @property
   def rawtext(self):
      if getattr(self, '_rawtext_local_change', False):
         return self._rawtext
      if not self.pk:
         return None
      from .documents import SubmissionDocument
      try:
         return SubmissionDocument.get(id=self.pk)._rawtext
      except:
         return None

   @rawtext.setter
   def rawtext(self, value):
      self._rawtext_local_change = True
      self._rawtext = value

documents.py

   @registry.register_document
   class SubmissionDocument(Document):

      rawtext = fields.TextField()

      def prepare_rawtext(self, instance):
         return instance.rawtext

tasks.py

   @shared_task
   def process_ocr(my_uuid)

      result = "test" # will ultimately be OCR'd text

      # note that you must do a save on property fields, can't do an update
      instance = Submission.objects.get(my_uuid=my_uuid)
      instance.rawtext = result
      instance.save()

1 Ответ

1 голос
/ 18 апреля 2020

Вы можете добавить дополнительные поля в определение документа, связанного с вашей моделью (см. Поле 'type_to_field' в документации https://django-elasticsearch-dsl.readthedocs.io/en/latest/fields.html#using -different-attribute-for-model-fields , и объединить это с метод prepare_xxx для инициализации пустой строки, если экземпляр создан, и его текущего значения в случае обновления) Это решит вашу проблему?

Правка 1 - Вот что я имел в виду:

models.py

class Submission(models.Model):
    @property
    def rawtext(self):
        if getattr(self, '_rawtext_local_change ', False):
            return self._rawtext
        if not self.pk:
            return None
        from .documents import SubmissionDocument
        return SubmissionDocument.get(meta__id=self.pk).rawtext

    @property.setter
    def rawtext(self, value):
        self._rawtext_local_change = True
        self._rawtext = value

Редактировать 2 - опечатка с фиксированным кодом

...