为什么这个错误发生 #
document_missing_exception 表示尝试更新或删除一个不存在的文档。当操作的文档 ID 在索引中找不到时,就会抛出此异常。
这个错误可能由以下原因引起:
- 文档 ID 不存在:提供的文档 ID 在索引中不存在
- 索引不匹配:文档在另一个索引中,而非当前索引
- 文档已被删除:文档在操作前被其他进程删除
- ID 类型错误:文档 ID 的类型(如字符串 vs 数字)不匹配
- 路由错误:使用了错误的路由值导致定位不到文档
- 时序问题:在文档索引后立即查询,但尚未刷新
- 并发操作:多个操作同时处理同一文档
如何修复这个错误 #
1. 检查文档是否存在 #
# 检查文档是否存在
GET /<index>/_doc/<id>
# 或使用 HEAD 请求(更快)
HEAD /<index>/_doc/<id>
2. 使用 upsert 操作 #
# 使用 upsert 在文档不存在时创建
POST /<index>/_update/<id>
{
"doc": {
"field": "value"
},
"upsert": {
"field": "value",
"other_field": "default_value"
}
}
3. 使用 doc_as_upsert #
# 使用 doc 作为 upsert 文档
POST /<index>/_update/<id>
{
"doc": {
"field": "value"
},
"doc_as_upsert": true
}
4. 检测文档不存在 #
# 使用 if_primary_term 进行条件更新
PUT /<index>/_doc/<id>?if_primary_term=1
{
"field": "value"
}
# 错误响应:404 Not Found
5. 使用批量操作时的处理 #
# 在批量操作中处理文档不存在
POST /_bulk
{ "update": { "_index": "<index>", "_id": "1", "retry_on_conflict": 3 } }
{ "doc": { "field": "value" }, "doc_as_upsert": true }
{ "update": { "_index": "<index>", "_id": "2", "retry_on_conflict": 3 } }
{ "doc": { "field": "value" }, "doc_as_upsert": true }
6. 查询后再操作 #
# 先查询文档是否存在
GET /<index>/_doc/<id>
# 如果存在,执行更新
POST /<index>/_update/<id>
{
"doc": {
"field": "value"
}
}
7. 处理路由问题 #
# 如果使用了自定义路由,确保操作时使用相同的路由
POST /<index>/_doc/<id>?routing=<user_id>
{
"field": "value"
}
# 更新时也要使用相同的路由
POST /<index>/_update/<id>?routing=<user_id>
{
"doc": {
"field": "new_value"
}
}
8. 使用乐观并发控制 #
# 使用序列号进行条件更新
POST /<index>/_update/<id>
{
"doc": {
"field": "value"
},
"if_seq_no": 5,
"if_primary_term": 1
}
9. 处理批量更新失败 #
# 批量操作时,某些文档可能不存在
# 检查响应中的 "result" 字段
# "not_found" 表示文档不存在
10. 使用条件更新 #
# 使用脚本进行条件更新
POST /<index>/_update/<id>
{
"script": {
"source": "if (ctx._source.field != null) { ctx._source.field = params.value }",
"lang": "painless"
},
"params": {
"value": "new_value"
}
}
预防措施 #
- 使用 upsert 而不是单独的 update 操作
- 在删除或更新前检查文档是否存在
- 实现客户端重试逻辑处理时序问题
- 使用条件更新避免并发冲突
- 对于关键操作,先查询再操作
- 使用适当的事务或锁机制处理并发
- 考虑使用外部版本号控制并发
- 在批量操作中使用 doc_as_upsert





