我正在使用:
- 弹性搜索:6.4.3
- 春季启动:2.1.9.发布
- 弹簧弹性搜索: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 分钟。
- 由于这是一个批处理应用程序,目前,以上对我来说是可以接受的。
- 虽然,我相信可以使用批量更新和批量更新请求来进一步改进它。