Spring & Elasticsearch: обновление нескольких документов на основе определенного поля и без идентификатора - PullRequest
0 голосов
/ 08 января 2020

Я использую:

  1. Elasticsearch: 6.4.3
  2. Spring Boot: 2.1.9.RELEASE
  3. Spring Elasticsearch: 6.4.3

У меня есть индекс в ES:

{
  "mapping": {
    "logi_info_index": {
      "properties": {
        "area": {
          "type": "text"
        },
        "createdBy": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "createdDate": {
          "type": "long"
        },
        "logiCode": {
          "type": "integer"
        },
        "esId": {
          "type": "keyword" -> @Id for ES
        },
        "geoPoint": {
          "type": "geo_point"
        },
        "isActive": {
          "type": "text"
        },
        "latitude": {
          "type": "text"
        },
        "longitude": {
          "type": "text"
        },
        "storeAddress": {
          "type": "text"
        },
        "storeName": {
          "type": "text"
        },
        "updatedBy": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "updatedDate": {
          "type": "long"
        }
      }
    }
  }
}

Теперь в этом индексе может быть около 50 тыс. Документов.

Для некоторых бизнес-логи c, я необходимо обновить все документы, которые удовлетворяют указанному c условию: isActive=0.

Пример:

У нас есть документы с isActive as 0 or 1.

  • Удалить все документы с isActive = 1 [=> Это возможно с DeleteQuery (deleteAll) <=] </li>
  • Поскольку теперь у нас есть только isActive = 0, мы хотим обновить оставшиеся документы isActive = 1.

У меня следующих вопросов :

  • Как мне обновить все документы со значением для поля спецификаций c, БЕЗ использования Id (как я делал при удалении) ?
  • Это вообще возможно ?
  • Если это возможно, я хочу использовать возможности Spring, чтобы это произошло.

Ответы [ 2 ]

0 голосов
/ 10 января 2020

Я сделал это с помощью клиента ES java и UpdateByQuery:

public void updateAll() {
    assert elasticsearchOperations != null;
    UpdateByQueryRequestBuilder updateByQuery = UpdateByQueryAction.INSTANCE
        .newRequestBuilder(elasticsearchOperations.getClient());
    updateByQuery.source(((Document) CommonUtility
        .getDoc(LogiEntity.class, Document.class)).indexName())
        .filter(query("isActive", AppConstants.TEMPORARY_ACTIVE))
        .script(script());
    BulkByScrollResponse response = updateByQuery.get();
    log.debug("process update: {}. Total updated records: {}",
        response.getStatus(), response.getUpdated());
  }

private Script script() {
    String updateCode =
        "if (ctx._source.isActive == '" + AppConstants.TEMPORARY_ACTIVE + "') "
            + "{"
            + "ctx._source.isActive = '" + AppConstants.ACTIVE + "';"
            + "}";
    return new Script(ScriptType.INLINE, "painless", updateCode,
        Collections.emptyMap());
  }

private QueryBuilder query(String fieldName, String value) {
    return QueryBuilders.matchQuery(fieldName, value);
  }
  • Я протестировал его с 1,5M записями в Elasticsearch, пытаясь обновить 1.2 M записывает и занимает около 1,5 минут .
  • Поскольку это пакетное приложение, на данный момент, выше, приемлемо для меня.
  • Хотя, я уверен, его можно еще улучшить, используя массовое обновление и пакетирование запросов на обновление.
0 голосов
/ 09 января 2020

Это невозможно в Spring Data Elasticsearch (который, как я полагаю, вы используете, так как этот вопрос помечен для этого).

Даже в «обычном» Elasticsearch это не легко, единственная возможность - это использовать Update By Query API в сочетании со сценарием (я только что адаптировал пример do c, не пробовал):

POST logi_info_index/_update_by_query
{
  "script": {
    "source": "ctx._source.isActive=1",
    "lang": "painless"
  },
  "query": {
    "match_all": {}
  }
}
...