Spring & Elasticsearch:根据特定字段更新多个文档,不带 ID



我正在使用:

  1. 弹性搜索:6.4.3
  2. 春季启动:2.1.9.发布
  3. 弹簧弹性搜索: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"
}
}
}
}
}

现在,在这个索引中可能有大约 50K 个文档。

对于某些业务逻辑,我需要更新满足特定条件的所有文档:isActive=0

例:

我们有文件,其中有isActive as 0 or 1.

  • 删除所有有isActive = 1的文档 [=> 这可以通过DeleteQuery(全部删除(<=]
  • 从现在开始,我们只有isActive = 0我们想用isActive = 1更新剩余的文档。

我有以下问题

  • 如何在不使用 Id 的情况下使用特定字段的值更新所有文档(就像我在删除中所做的那样(?
  • 这可能吗?
  • 如果可能的话,我想利用Spring的能力来实现它。

这在Spring Data Elasticsearch中是不可能的(我假设你使用它,因为这个问题是为此标记的(。

即使在"普通"Elasticsearch中,这也不容易,唯一的可能性是将按查询更新API与脚本结合使用(我只是改编了文档示例,没有尝试(:

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

我使用 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 分钟
  • 由于这是一个批处理应用程序,目前,以上对我来说是可以接受的。
  • 虽然,我相信可以使用批量更新和批量更新请求来进一步改进它。

最新更新