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

为什么这个错误发生 #

routing_missing_exception 表示执行操作时缺少必需的路由信息。路由(routing)值用于确定文档存储在哪个分片上,某些操作需要明确指定路由值。

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

  1. 缺少路由参数:请求中未提供必需的路由值
  2. 自定义路由映射:索引配置了自定义路由映射
  3. 父文档关系:使用父子关系时需要路由值
  4. 分片路由:操作需要特定分片但未提供路由
  5. 客户端配置错误:客户端未正确配置路由
  6. 默认路由不适用:默认路由机制不适用于该操作

如何修复这个错误 #

1. 提供路由值 #

# 在请求中添加路由参数
GET /<index>/_doc/<id>?routing=<routing_value>

POST /<index>/_doc/<id>?routing=<routing_value>
{
  "field": "value"
}

2. 使用文档 ID 作为路由 #

# 如果文档 ID 与路由值相同,可以设置默认路由
PUT /<index>/_mapping
{
  "settings": {
    "index.routing.allocation.include._tier_preference": "data_hot"
  }
}

3. 配置映射中的路由 #

# 在索引创建时配置路由
PUT /<index>
{
  "mappings": {
    "_routing": {
      "required": true
    }
  }
}

4. 查看映射配置 #

# 查看索引的路由配置
GET /<index>/_mapping?filter_path=**._routing

# 查看所有设置
GET /<index>/_settings

5. 更新客户端配置 #

// 在客户端配置路由
IndexRequest request = new IndexRequest("<index>");
request.id("<id>");
request.routing("<routing_value>");
request.source(...);

6. 使用批量 API 时提供路由 #

# 批量操作时为每个文档指定路由
POST /_bulk
{ "index": { "_index": "<index>", "_id": "1", "routing": "user1" } }
{ "field": "value1" }
{ "index": { "_index": "<index>", "_id": "2", "routing": "user2" } }
{ "field": "value2" }

7. 父子文档路由 #

# 对于父子关系,使用父文档 ID 作为路由
POST /<index>/_doc/<child_id>?routing=<parent_id>
{
  "join": {
    "name": "child",
    "parent": "<parent_id>"
  },
  "field": "value"
}

8. 搜索时使用路由 #

# 搜索时指定路由以提高性能
GET /<index>/_search?routing=<routing_value>
{
  "query": {
    "match": {
      "field": "value"
    }
  }
}

9. 删除时提供路由 #

# 删除文档时需要路由值
DELETE /<index>/_doc/<id>?routing=<routing_value>

# 或通过查询删除
POST /<index>/_delete_by_query?routing=<routing_value>
{
  "query": {
    "term": {
      "field": "value"
    }
  }
}

10. 更新时提供路由 #

# 更新文档时需要路由值
POST /<index>/_update/<id>?routing=<routing_value>
{
  "doc": {
    "field": "new_value"
  }
}

11. 配置默认路由 #

# 可以配置一个字段作为默认路由
PUT /<index>
{
  "mappings": {
    "_routing": {
      "required": true,
      "path": "user_id"
    }
  }
}

12. 批量导入时处理路由 #

// 批量导入时为每个文档生成路由
BulkRequest bulkRequest = new BulkRequest();
for (Document doc : documents) {
    IndexRequest indexRequest = new IndexRequest("<index>");
    indexRequest.id(doc.getId());
    indexRequest.routing(doc.getUserId()); // 使用用户 ID 作为路由
    indexRequest.source(doc.toJson());
    bulkRequest.add(indexRequest);
}

13. 验证路由配置 #

# 确认路由配置正确
GET /<index>/_mapping?filter_path=**.mappings._routing

# 检查是否必需
GET /<index>/_mapping?filter_path=**.mappings._routing.required

14. 搜索多个路由值 #

# 可以指定多个路由值
GET /<index>/_search?routing=value1,value2,value3
{
  "query": {
    "match_all": {}
  }
}

15. 使用别名处理路由 #

# 创建包含路由值的别名
POST /_aliases
{
  "actions": [
    {
      "add": {
        "index": "<index>",
        "alias": "<index>_alias",
        "routing": "routing_value"
      }
    }
  ]
}

预防措施 #

  • 在索引创建时明确路由要求
  • 在客户端代码中配置默认路由
  • 为父子关系使用正确的路由
  • 在批量操作中包含路由值
  • 文档化路由配置
  • 使用有意义的路由值
  • 监控路由缺失错误
  • 实现客户端验证
  • 使用映射中的路由路径
  • 测试所有操作的配置