通过指向多索引的Elasticsearch别名更新单文档的最优方案咨询
性能对比
- 第二种方案性能明显更高。
_update_by_query的执行逻辑是先扫描别名绑定的所有索引的全部分片匹配目标文档,再执行脚本更新,哪怕仅命中1条文档,也要走完整的批量更新流程,额外包含脚本解析、全分片写权限校验、冲突自动重试等开销,性能远低于单点更新。- 第二种方案的第一步查询仅做只读操作,开销极低,第二步直接针对具体索引的指定文档做单点更新,能直接路由到目标分片,不需要扫描其他无关分片,单请求耗时比第一种低30%以上,高并发场景下性能差距会拉大到数倍。
推荐方案
常规场景优先选择第二种方案,仅当你需要更新别名下所有匹配相同_id的文档时,才使用_update_by_query。
需要注意:如果业务中存在不同索引下有相同_id的文档,_update_by_query会更新所有命中的文档,而第二种方案默认只会更新查询返回的第一条匹配文档,需要根据业务需求调整逻辑。
更优实现方式
可以把第一步的_search查询替换为更轻量的文档点查接口:
GET my-alias/_doc/my-id-to-update
该接口比_search开销低很多,返回结果中直接包含文档所属的_index元数据,拿到后再执行_update即可,比原第二种方案性能还要好。如果目标文档不存在,该接口会直接返回404,不需要再执行后续更新操作,判断逻辑也更简单。
如果业务可改造,还可以在写入阶段给所有文档配置全局唯一的路由键,查询时指定routing参数,进一步减少需要扫描的分片数量,提升查询效率。
内容的提问来源于stack exchange,提问作者Rich Sutton
相关产品推荐
相关产品推荐

