0

ドキュメントとそれに関連するメタデータを保存する Django Web アプリケーションを構築しています。

メタデータの大部分は基盤となる MySQL データベースに保存され、OCR されたドキュメント テキストは Elasticsearch でインデックス化され、全文検索が可能になります。モデルで見つかった他のいくつかのフィールドにもインデックスを付けている (したがって、二重に格納している) ため、データ モデルを接続して同期するためにdjango-elasticsearch-dslを組み込みました。Haystackの使用を検討していましたが、Elasticsearch の最新バージョンをサポートしていません。

ドキュメントがアプリケーションの管理インターフェイスを介してアップロードされると、post_save シグナルが自動的に Celery 非同期バックグラウンド タスクをトリガーしOCR を実行し、最終的に抽出されたテキストを Elasticsearch にインデックス付けします。

モデルに全文フィールドが定義されていないことを見て (データベースに CLOB を保存したり検索したりしたくないので、そうしないことを望んでいます)、更新のベスト プラクティスを探しています。私のtasks.pyファイルからの私のElasticsearchドキュメント。django-elasticseach-dsl を使用してそうする方法はないようです (しかし、おそらく私が間違っているのでしょうか?)。

  1. 姉妹のdjango-elasticsearch-dsl-drfパッケージを使用して、REST 経由で Elasticsearch とのインターフェースを試みます。

  2. よりバニラのelasticsearch-dsl-pyパッケージ(elasticsearch-pyに基づく)を使用して、アプリケーションをElasticsearchとより大まかに統合します。少なくともモデルに信号を接続したい場合は、もう少し統合コードを書かなければならないので、このアプローチではいくらか「贅沢」を失うでしょう。

ベストプラクティスはありますか? または、私が検討していない別のアプローチですか?

更新 1: @Nielk からの回答を実装しようとすると、OCR されたテキスト (result = "test" in tasks.py below) を ElasticSearch に永続化できますが、MySQL データベースにも永続化されます。基本的に Submission.rawtext を ElasticSearch へのパススルーとして構成する方法について、私はまだ混乱しています。

models.py:

class Submission(models.Model):

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

ドキュメント.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

ドキュメント.py

   @registry.register_document
   class SubmissionDocument(Document):

      rawtext = fields.TextField()

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

タスク.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()
4

1 に答える 1

1

モデルにリンクされたドキュメント定義にフィールドを追加できます (ドキュメントhttps://django-elasticsearch-dsl.readthedocs.io/en/latest/fields.html#using-different-attributesの「type_to_field」フィールドを参照してください)。 -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 - コードのタイプミスを修正

于 2020-04-18T06:41:12.613 に答える