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