Spring&Elasticsearch:在特定字段的基础上更新多个文档,不带ID

时间:2020-01-08 16:57:14

标签: spring elasticsearch spring-data-elasticsearch

我正在使用:

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

我在ES中有一个索引:

predict_type<-"probability"

现在,该索引中可能有约5万个文档。

对于某些业务逻辑,我需要更新所有满足特定条件的文档:{ "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" } } } } }

示例:

我们有包含isActive=0的文档。

  • 删除所有包含isActive as 0 or 1的文档 [=>这可以通过isActive = 1(deleteAll)<=]
  • 因为现在我们只有DeleteQuery,所以我们要用isActive = 0更新其余文档。

我有以下问题

  • 如何使用特定字段的值不使用ID (就像我在删除操作中一样)来更新所有文档?
  • 这可能吗?
  • 如果可能,我想使用Spring的功能来实现它。

2 个答案:

答案 0 :(得分:0)

这在Spring Data Elasticsearch中是不可能的(我假设您使用,因为为此问题加上了标签)。

即使在“普通” Elasticsearch中这也不容易,唯一可能的是将Update By Query API与脚本结合使用(我只是改写了doc示例,没有尝试过):

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

答案 1 :(得分:0)

我是使用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);
  }
  • 我用Elasticsearch中的 1.5M 记录对其进行了测试,试图更新1.2M 记录,大约需要花费 1.5分钟
  • 由于这是一个批处理应用程序,因此目前,上面对我来说是可以接受的。
  • 尽管如此,我相信可以使用批量更新和批量更新请求来进一步改善它。