Django Celery 任务中的 Elasticsearch 索引
Elasticsearch Indexing in Django Celery Task
我正在构建一个 Django 网络应用程序来存储文档及其关联的元数据。
大部分元数据将存储在底层 MySQL 数据库中,OCR 文档文本在 Elasticsearch 中建立索引以启用全文搜索。我已经合并了 django-elasticsearch-dsl to connect and synchronize my data models, as I’m also indexing (and thus, double-storing) a few other fields found in my models. I had considered using Haystack,但它不支持最新的 Elasticsearch 版本。
当通过应用程序的管理界面上传文档时,post_save 信号会自动触发 Celery 异步后台任务来执行 OCR,并最终将提取的文本索引到 Elasticsearch 中。
鉴于我没有在我的模型中定义全文字段(并且希望避免这样做,因为我不想在数据库中存储或搜索 CLOB),我正在寻找从我的 tasks.py 文件更新我的 Elasticsearch 文档的最佳实践。使用 django-elasticseach-dsl 似乎没有办法做到这一点(但也许我错了?)所以我想知道我是否应该这样做:
尝试使用姐妹 django-elasticsearch-dsl-drf 包通过 REST 与 Elasticsearch 交互。
通过使用 more vanilla elasticsearch-dsl-py 包(基于 elasticsearch-py)更松散地将我的应用程序与 Elasticsearch 集成。使用这种方法我会失去一些“奢侈”,因为我必须编写更多的集成代码,至少如果我想用信号连接我的模型。
有最佳实践吗?或者我没有考虑过的其他方法?
更新 1:
在尝试实现@Nielk 的答案时,我能够将 OCR 文本(下面 tasks.py 中的结果 = "test")保存到 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
class投稿(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()
您可以在链接到您的模型的文档定义中添加额外字段(请参阅文档 https://django-elasticsearch-dsl.readthedocs.io/en/latest/fields.html#using-different-attributes-for-model-fields 中的字段 'type_to_field' ,并将其与 '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 - 修复了代码拼写错误
我正在构建一个 Django 网络应用程序来存储文档及其关联的元数据。
大部分元数据将存储在底层 MySQL 数据库中,OCR 文档文本在 Elasticsearch 中建立索引以启用全文搜索。我已经合并了 django-elasticsearch-dsl to connect and synchronize my data models, as I’m also indexing (and thus, double-storing) a few other fields found in my models. I had considered using Haystack,但它不支持最新的 Elasticsearch 版本。
当通过应用程序的管理界面上传文档时,post_save 信号会自动触发 Celery 异步后台任务来执行 OCR,并最终将提取的文本索引到 Elasticsearch 中。
鉴于我没有在我的模型中定义全文字段(并且希望避免这样做,因为我不想在数据库中存储或搜索 CLOB),我正在寻找从我的 tasks.py 文件更新我的 Elasticsearch 文档的最佳实践。使用 django-elasticseach-dsl 似乎没有办法做到这一点(但也许我错了?)所以我想知道我是否应该这样做:
尝试使用姐妹 django-elasticsearch-dsl-drf 包通过 REST 与 Elasticsearch 交互。
通过使用 more vanilla elasticsearch-dsl-py 包(基于 elasticsearch-py)更松散地将我的应用程序与 Elasticsearch 集成。使用这种方法我会失去一些“奢侈”,因为我必须编写更多的集成代码,至少如果我想用信号连接我的模型。
有最佳实践吗?或者我没有考虑过的其他方法?
更新 1: 在尝试实现@Nielk 的答案时,我能够将 OCR 文本(下面 tasks.py 中的结果 = "test")保存到 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 class投稿(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()
您可以在链接到您的模型的文档定义中添加额外字段(请参阅文档 https://django-elasticsearch-dsl.readthedocs.io/en/latest/fields.html#using-different-attributes-for-model-fields 中的字段 'type_to_field' ,并将其与 '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 - 修复了代码拼写错误