Обновите все документы elasticsearch, используя dict для ввода с помощью Python.

У меня есть вариант использования, когда мне нужно обновить все документы elasticsearch. В моем индексе у меня есть источник, который выглядит примерно так:

      {'_source': {
 'employee_ids': ['J1234', 'J28373', 'CH1234', 'J98823', 'J1234'],
 'non_employee_ids': [],
 'friends_id': ['CH1234', 'J98823', 'J28373', 'H82739', 'J98823'],
 'local_date': '2022/01/10',
 'local': True
} 

Каждый день я получаю новый список employee_id и связанных с ними друзей. Это при условии, что ничего не нужно решать. Полученные данные похожи на словарь python или объект json, где ключами являются old_ids, а значениями — new_ids. Такие как

      {'J1234': 'J2875', 'CH1234': 'J2879'}

Я написал безболезненный скрипт для обновления идентификаторов, однако он требует цикла for для каждого списка, который мы хотим обновить. Это может быть выполнено через UpdateByQuery в elasticsearch_dslбиблиотека.

      def result = [];
for (def item: ctx._source.employee_ids) 
    { 
        if (item == params.fromId) {
        gal_res.add(params.toId)
    } 
    else {
        gal_res.add(item)
    }} ctx._source.employee_ids= result; 

def resultF = [];
for (def item: ctx._source.friends_id) 
    { 
        if (item == params.fromId) {
        gal_res.add(params.toId)
    } 
    else {
        gal_res.add(item)
    }} ctx._source.friends_id = resultF ; 

Вопросы. Есть ли более необязательное решение для обновления всех документов и списков полей без необходимости перебирать словарь Python один за другим, чтобы обновить все документы, соответствующие этому единственному идентификатору сотрудника?

Есть ли способ отправить словарь, чтобы найти все документы, соответствующие ключам, а затем обновить значения? В одной команде?

1 ответ

Готового решения для этого нет.

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

      PUT /test_replace_id/
{
  "mappings": {
    "properties": {
      "employee_ids":{
        "type": "keyword"
      }
    }
  }
}

POST /test_replace_id/_doc/1
{
  "employee_ids": ["old1","old2"],
  "frieds_id": "old1"
}

POST /test_replace_id/_update/1
{
  "script": {
    "source": """
      for (t in params.targets){
        if (ctx._source[t] instanceof List){
          for (int j=0; j<ctx._source[t].length; j++){
            if (params.map.containsKey(ctx._source[t][j])) {
              ctx._source[t][j] = params.map.get(ctx._source[t][j])
            }
          }
        }else{
          if (params.map.containsKey(ctx._source[t])) {
            ctx._source[t] = params.map.get(ctx._source[t])
          }
        }
      }
    """,
    "params":{
      "targets": ["employee_ids","frieds_id"],
      "map": {"old1":"new1"}
    }
  }
}
GET /test_replace_id/_search

Это обеспечивает большую гибкость и не требует повторения и обновления. Теперь мы можем отправить весь запрос сразу.

@Tomo_M за решение!

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