部分更新指定 ID 的文档,支持使用脚本或字段更新。
API #
POST /{index}/_update/{id}
API 的作用 #
该 API 用于部分更新文档,与 /_doc API(完全替换)不同,此 API 只修改指定的字段。
更新方式 #
| 方式 | 描述 |
|---|---|
| Doc 更新 | 直接提供要更新的字段 |
| Script 更新 | 使用脚本动态更新文档 |
核心特性 #
| 特性 | 描述 |
|---|---|
| 部分更新 | 只修改指定字段,保留其他字段 |
| Upsert | 文档不存在时自动创建 |
| 并发控制 | 支持乐观并发控制 |
| 脚本支持 | 支持使用 Painless 等脚本语言 |
API 的参数 #
路由参数 #
| 参数 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
{index} | 字符串 | 必需 | 索引名称 |
{id} | 字符串 | 必需 | 文档 ID |
Query String 参数 #
| 参数 | 类型 | 是否必填 | 默认值 | 描述 |
|---|---|---|---|---|
routing | 字符串 | 否 | - | 路由值 |
timeout | 时间值 | 否 | 30s | 操作超时时间 |
refresh | 字符串 | 否 | false | 刷新策略:true、false、wait_for |
wait_for_active_shards | 字符串 | 否 | 1 | 等待活跃分片数:1、all、具体数字 |
retry_on_conflict | 整数 | 否 | 0 | 版本冲突时的重试次数 |
doc_as_upsert | 布尔值 | 否 | false | 将 doc 内容作为 upsert 使用 |
if_seq_no | 整数 | 否 | -1 | 序列号条件 |
if_primary_term | 整数 | 否 | -1 | 主版本条件 |
_source | 布尔值/字符串 | 否 | true | 是否返回更新后的文档源 |
_source_include | 字符串 | 否 | - | 包含的字段模式 |
_source_exclude | 字符串 | 否 | - | 排除的字段模式 |
请求体参数 #
请求体必须包含以下字段之一:
使用 Doc 更新 #
{
"doc": {
"field1": "new value",
"field2": 123
}
}
使用 Script 更新 #
{
"script": {
"source": "ctx._source.counter += params.count",
"lang": "painless",
"params": {
"count": 5
}
}
}
使用 Upsert(文档不存在时创建) #
{
"doc": {
"field1": "value"
},
"upsert": {
"field1": "default value",
"field2": 0
}
}
使用 doc_as_upsert #
{
"doc": {
"field1": "value",
"field2": 456
},
"doc_as_upsert": true
}
示例 #
Doc 更新 #
POST /my_index/_update/1
{
"doc": {
"user": "new_user",
"status": "active"
}
}
响应示例:
{
"_index": "my_index",
"_type": "_doc",
"_id": "1",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1,
"get": {
"_source": {
"user": "new_user",
"status": "active"
}
}
}
Script 更新 #
POST /my_index/_update/1
{
"script": {
"source": "ctx._source.counter += params.count",
"lang": "painless",
"params": {
"count": 5
}
}
}
Upsert(文档不存在时创建) #
POST /my_index/_update/1
{
"doc": {
"views": 1
},
"upsert": {
"views": 0,
"created_at": "2026-02-04"
}
}
doc_as_upsert #
POST /my_index/_update/1
{
"doc": {
"name": "Product",
"price": 99.99
},
"doc_as_upsert": true
}
条件更新 #
POST /my_index/_update/1?if_seq_no=5&if_primary_term=1
{
"doc": {
"status": "updated"
}
}
重试冲突 #
POST /my_index/_update/1?retry_on_conflict=3
{
"script": {
"source": "ctx._source.counter++"
}
}
不返回文档源 #
POST /my_index/_update/1?_source=false
{
"doc": {
"field": "value"
}
}
返回特定字段 #
POST /my_index/_update/1?_source_includes=name,status
{
"doc": {
"status": "active"
}
}
使用路由 #
POST /my_index/_update/1?routing=user1
{
"doc": {
"last_login": "2026-02-04"
}
}
多字段更新 #
POST /products/_update/1
{
"doc": {
"name": "Updated Product",
"price": 149.99,
"in_stock": true
}
}
复杂脚本更新 #
POST /counter/_update/1
{
"script": {
"source": """
if (ctx._source.containsKey('tags') == false) {
ctx._source.tags = new ArrayList();
}
if (params.tags.contains(ctx._source.tags) == false) {
ctx._source.tags.addAll(params.tags);
}
""",
"lang": "painless",
"params": {
"tags": ["important", "featured"]
}
}
}
获取更新后的文档 #
POST /my_index/_update/1
{
"doc": {
"status": "processed"
}
}
响应中会包含更新后的文档内容。
响应字段说明 #
| 字段 | 描述 |
|---|---|
_index | 文档所在的索引 |
_type | 文档类型(固定为 _doc) |
_id | 文档 ID |
_version | 文档版本号 |
result | 操作结果:updated、noop、created |
_shards | 分片信息 |
_seq_no | 序列号 |
_primary_term | 主版本号 |
get | 更新后的文档(如果 _source=true) |
操作结果 #
| 结果 | 描述 |
|---|---|
updated | 文档已更新 |
noop | 文档内容无变化 |
created | 通过 upsert 创建了新文档 |
错误处理 #
文档不存在(未使用 upsert) #
{
"error": {
"type": "document_missing_exception",
"reason": "document [1] missing"
},
"status": 404
}
版本冲突 #
{
"error": {
"type": "version_conflict_engine_exception",
"reason": "[1]: version conflict"
},
"status": 409
}
脚本错误 #
{
"error": {
"type": "script_exception",
"reason": "runtime error"
},
"status": 400
}
并发控制 #
使用序列号和主版本 #
POST /my_index/_update/1?if_seq_no=10&if_primary_term=1
{
"doc": {
"status": "updated"
}
}
只有在文档的序列号为 10 且主版本为 1 时才会执行更新。
重试机制 #
POST /my_index/_update/1?retry_on_conflict=3
{
"script": {
"source": "ctx._source.counter++"
}
}
当发生版本冲突时,会自动重试最多 3 次。
使用场景 #
场景 1:计数器更新 #
POST /counters/_update/page_views
{
"script": {
"source": "ctx._source.count++",
"lang": "painless"
},
"upsert": {
"count": 1
}
}
场景 2:条件更新 #
POST /users/_update/123
{
"doc": {
"last_login": "2026-02-04T08:00:00"
}
}
场景 3:数组操作 #
POST /articles/_update/1
{
"script": {
"source": "ctx._source.tags.add(params.tag)",
"lang": "painless",
"params": {
"tag": "featured"
}
}
}
场景 4:批量字段更新 #
POST /products/_update/1
{
"doc": {
"name": "New Name",
"price": 99.99,
"category": "Electronics",
"updated_at": "2026-02-04"
}
}
脚本语言 #
Painless(推荐) #
{
"script": {
"source": "ctx._source.field = params.value",
"lang": "painless",
"params": {
"value": 123
}
}
}
脚本上下文 #
| 变量 | 描述 |
|---|---|
ctx._source | 文档的源数据 |
ctx.op | 操作类型:none、delete |
params | 传递给脚本的参数 |
性能考虑 #
| 操作 | 性能影响 |
|---|---|
| Doc 更新 | 需要读取、修改、写回整个文档 |
| Script 更新 | 需要编译和执行脚本,较慢 |
| 重试冲突 | 增加延迟 |
| 返回 _source | 增加响应大小 |
注意事项 #
- 不支持版本控制:更新 API 不支持
version参数 - 完整文档读取:即使更新一个字段,也需要读取整个文档
- 脚本开销:脚本更新比 doc 更新开销更大
- 并发控制:使用
if_seq_no和if_primary_term而非version - 类型已弃用:有类型的更新 API 已被弃用





