Частично обновление значения поля списка elasticsearch с использованием python

Цель этого вопроса — спросить сообщество, как частично обновить поле, не удаляя какое-либо другое содержимое этого поля.

В StackOverflow есть много примеров частичного обновления полей _source ElasticSearch с использованием python, curl и т. д. Библиотека python elasticsearch поставляется с elasticsearch.helpersпапка с функциями - parallel_bulk, streaming_bulk, bulk, которые позволяют разработчикам легко обновлять документы.

Если у пользователей есть данные в кадре данных pandas, можно легко перебрать строки, чтобы создать генератор для обновления/создания документов в elasticsearch. Документы Elasticsearch являются неизменяемыми, поэтому, когда происходит обновление, elasticsearch использует передаваемую информацию для создания нового документа, увеличивая версию документов и обновляя то, что необходимо обновить. Если в документе есть поле в виде списка, если запрос на обновление имеет одно значение, он заменит весь список этим новым значением. (Многие SO QA охватывают это). Я не хочу заменять значение этого списка новым значением, а вместо этого обновлять одно значение в списке до нового значения.

Например, в моем _source у меня есть поле как ['101 проселочная дорога', '35 парковая дорога', '277 громовая дорога']. Это поле имеет три значения, но, скажем, мы понимаем, что этот документ неверен, и нам нужно обновить «диск 101 страны» на «диск 1001 страны».

Я не хочу удалять другие значения в списке, вместо этого я хочу только обновить значение индекса новым значением.

Нужно ли мне писать безболезненный скрипт для выполнения этого действия, или есть другой способ выполнить это действие?

Пример: Хотите обновить документ От ---

      {'took': 176,
 'timed_out': False,
 '_shards': {'total': 1, 'successful': 1, 'skipped': 0, 'failed': 0},
 'hits': {'total': {'value': 0, 'relation': 'eq'},
  'max_score': None,
  'hits': [{'_index': 'docobot', '_type': '_doc', '_id': '19010239', 
'_source': {'name': 'josephine drwaler', 'address': ['101 country drive', '35 park drive', '277 thunderroad belway']
}}]}}

к

      {'took': 176,
 'timed_out': False,
 '_shards': {'total': 1, 'successful': 1, 'skipped': 0, 'failed': 0},
 'hits': {'total': {'value': 0, 'relation': 'eq'},
  'max_score': None,
  'hits': [{'_index': 'docobot', '_type': '_doc', '_id': '19010239', 
'_source': {'name': 'josephine drwaler', 'address': ['1001 country drive', '35 park drive', '277 thunderroad belway']
}}]}}

Обратите внимание, что адрес обновляется только для первого индекса, но номер индекса не должен влиять на обновление значения адреса в _source.

Каков наиболее эффективный и питонический способ частичного обновления документов в elasticsearch при сохранении целостности оставшихся значений в этом поле?

2 ответа

в_sourceэто то, что передается Elasticsearch в запросе API, это не «поле» в том же контексте, что считается

значит надо менять целиком addressполе с тем, что вы хотите, а не только со значением, которое вы хотите исправить. Elasticsearch предполагает, что вы передаете то, чем должно быть полное значение поля, и перезапишет это поле тем, что оно получило.

Нужно создать безболезненный скрипт для обновления. При этом нужно помнить, что вы можете получить доступ к любому полю в исходном коде:

      ctx._source.address = ['1001 country drive', '35 park drive', '277 thunderroad belway']

Но это не решает проблемы...

Поле представляет собой список, поэтому нам нужно выполнить итерацию по списку. Ниже безболезненный скрипт перебирает каждый элемент, сравнивает его с параметром поиска, если он совпадает, возвращает ответ.

      def upd_address= [];
for (def item: ctx._source.address) ]
{ 
  if (item == params.search_id) {
   upd_address.add(params.answer)
    } 
  else {
   upd_address.add(item)
 }} ctx._source.address = upd_address; 

Вы можете использовать вышеуказанное с elasticsearch_dsl как

      ubq = UpdateByQuery(using=[your es connection], doc_type='doc', index=['your index']
ubq = ubq.script(source=[above query], params={'search_id': addrss, 'answer': upd_addrss)
res = ubq.execute()
print(res, type(res))

Обновить цикл запроса для каждого элемента в списке. Проверяет, является ли элемент идентификатором поиска, если да, оставьте ответ, иначе сохраните тот же идентификатор.