📣 极限科技诚招搜索运维工程师(Elasticsearch/Easysearch)- 全职/北京 👉 : 立即申请加入

为什么这个错误发生 #

document_missing_exception 表示尝试更新或删除一个不存在的文档。当操作的文档 ID 在索引中找不到时,就会抛出此异常。

这个错误可能由以下原因引起:

  1. 文档 ID 不存在:提供的文档 ID 在索引中不存在
  2. 索引不匹配:文档在另一个索引中,而非当前索引
  3. 文档已被删除:文档在操作前被其他进程删除
  4. ID 类型错误:文档 ID 的类型(如字符串 vs 数字)不匹配
  5. 路由错误:使用了错误的路由值导致定位不到文档
  6. 时序问题:在文档索引后立即查询,但尚未刷新
  7. 并发操作:多个操作同时处理同一文档

如何修复这个错误 #

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