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

适用版本: 5.6-7.x(typed API 已废弃,8.x 已移除)

1. 错误异常的基本描述 #

Failed to get type [type] and id [id] 出现在旧版带 type 的 Get API 路径中,表示 Elasticsearch 在通过 Lucene reader 读取该文档的 stored fields 时失败。它与 typeless 版本的 Failed to get id [id] 类似,但这里仍处于历史的 typed document 读取模型下,涉及 type 和 id 两个维度。

常见现象 #

  • 旧版接口如 GET /index/type/id 返回 500 内部服务器错误。
  • 问题通常只影响少量文档或个别分片,其他文档可以正常读取。
  • 日志里常带 IOException、reader 读取失败或段文件异常,例如 read past EOFCorrupt index
  • 如果是批量查询(_mget)中使用 typed 格式,只有特定 type 和 id 的组合会失败。
  • 在 Elasticsearch 7.x 中,虽然默认不推荐,但 typed API 仍然可用;在 8.x 中,type 已被完全移除,此错误不再出现(会返回不同的错误)。

典型报错与异常栈 #

常见日志形态通常类似下面这样:

ElasticsearchException: Failed to get type [my_type] and id [abc123]
Caused by: java.io.IOException: read past EOF
	at org.apache.lucene.index.SegmentReader.document(SegmentReader.java:...)

或者段文件损坏:

ElasticsearchException: Failed to get type [_doc] and id [xyz789]
Caused by: java.io.IOException: Corrupt index
	at org.apache.lucene.codecs.StoredFieldsReader...

或者文件句柄问题:

ElasticsearchException: Failed to get type [logs] and id [doc456]
Caused by: java.io.IOException: Too many open files

2. 为什么会发生这个错误 #

Failed to get type [type] and id [id] 的根因是"在旧版 typed Get 请求中,读取文档 stored fields 失败"。从日志片段看,异常发生在 docIdAndVersion.reader.document(docIdAndVersion.docId, fieldVisitor)。这一步直接从底层 reader 读取目标文档字段;只要字段文件、reader 或底层存储异常,就会包装成当前错误。

常见原因通常包括:

  • 旧索引段文件损坏:历史 typed 索引的 Lucene 段文件(.fdt.fdx.si 等)损坏或数据不完整。
  • 分片状态不稳定:分片正在恢复、迁移或关闭,导致 reader 状态异常或不一致。
  • 底层存储瞬时不可用:磁盘故障、文件系统错误、网络存储(如 NFS)断开,导致 Lucene 读取失败。
  • 节点资源异常:磁盘空间不足、文件句柄耗尽(too many open files)、I/O 等待过高。
  • 索引升级遗留问题:从旧版本(如 5.x、6.x)升级到新版本(如 7.x)后,历史 typed 索引在升级过程中遗留了底层读取问题。
  • type 相关兼容性问题:在版本迁移过程中,type 的处理逻辑可能发生变化,导致某些历史数据读取失败。
  • 段合并异常:在段合并过程中,某些段文件被意外删除或覆盖,影响 typed 文档的读取。

3. 如何排查和解决这个异常和解决这个异常 #

建议按"先确认 API 版本、再定位影响范围、后检查存储健康"的顺序处理:

  1. 确认 API 版本:检查调用的是否是旧版 typed API 或内部兼容路径,考虑迁移到 typeless API。

    # 旧版 typed API(不推荐)
    curl -X GET "localhost:9200/my_index/my_type/my_id"
       
    # 新版 typeless API(推荐)
    curl -X GET "localhost:9200/my_index/_doc/my_id"
    
  2. 检查异常影响范围:确认问题是否只影响特定 type、特定文档或特定分片。

    # 查看索引中的 type 分布(7.x 中通常只有 _doc)
    curl -X GET "localhost:9200/my_index/_mapping?pretty"
       
    # 尝试获取其他文档,确认是否只有特定文档失败
    curl -X GET "localhost:9200/my_index/_doc/other_id"
    
  3. 查看节点日志:从 Elasticsearch 节点日志中找到这个异常对应的底层 caused by

    # 查看相关错误日志
    grep -r "Failed to get type" /var/log/elasticsearch/
    grep -r "IOException" /var/log/elasticsearch/ | tail -50
    
  4. 检查分片状态:确认分片是否处于恢复、迁移、关闭或异常状态。

    # 查看分片分配和状态
    curl -X GET "localhost:9200/_cat/shards/my_index?v"
       
    # 查看未分配分片的原因
    curl -X GET "localhost:9200/_cluster/allocation/explain?pretty"
    
  5. 检查磁盘和文件系统:查看磁盘空间、I/O 状态和文件句柄使用情况。

    # 检查磁盘空间
    df -h
       
    # 检查磁盘 I/O 错误
    dmesg | grep -i "error\|io\|ext4\|xfs"
       
    # 检查文件句柄使用
    lsof -p $(pgrep -f elasticsearch) | wc -l
    
  6. 检查索引升级历史:如果索引是从旧版本升级而来,确认是否存在旧索引长期遗留问题。

    # 查看索引创建版本(通过 settings)
    curl -X GET "localhost:9200/my_index/_settings?pretty" | grep "version"
    

排查时需要注意的问题 #

  • 这个错误出现在旧版 typed API 中,如果可能,建议迁移到 typeless API(去掉 URL 中的 type 部分)。
  • 如果问题只出现在特定 type 上,可能是该 type 对应的数据有问题,需要重点检查。
  • 对于历史 typed 索引,需要考虑是否值得修复,还是直接迁移到新索引(typeless)。

4. 如何解决这个错误 #

常用修复思路 #

  • 迁移到 typeless API:如果使用的是 7.x 或更高版本,建议迁移到 typeless API,避免 typed API 的兼容性问题。

    # 旧版 typed API(避免使用)
    curl -X GET "localhost:9200/my_index/my_type/my_id"
      
    # 新版 typeless API(推荐使用)
    curl -X GET "localhost:9200/my_index/_doc/my_id"
    
  • 通过副本恢复分片:如果主分片数据损坏,可以尝试分配副本分片来恢复。

    # 尝试分配副本分片
    curl -X POST "localhost:9200/_cluster/reroute" -H 'Content-Type: application/json' -d'
    {
      "commands": [
        {
          "allocate_replica": {
            "index": "my_index",
            "shard": 0,
            "node": "target_node_name"
          }
        }
      ]
    }
    '
    
  • 重建索引:对历史 typed 索引,考虑重建为 typeless 索引,同时修复数据问题。

    # 重建索引(从旧索引到新索引)
    curl -X POST "localhost:9200/_reindex?pretty" -H 'Content-Type: application/json' -d'
    {
      "source": {
        "index": "old_typed_index"
      },
      "dest": {
        "index": "new_typeless_index"
      }
    }
    '
    
  • 从快照恢复:如果有快照备份,可以从快照恢复受损的索引。

    # 从快照恢复索引
    curl -X POST "localhost:9200/_snapshot/my_backup/snapshot_1/_restore" -H 'Content-Type: application/json' -d'
    {
      "indices": "my_index",
      "ignore_unavailable": true,
      "include_global_state": false
    }
    '
    
  • 删除损坏文档:如果只有个别文档损坏,可以尝试删除后重新索引。

    # 删除损坏的文档(需要知道文档 ID)
    curl -X DELETE "localhost:9200/my_index/my_type/my_id"
    

后续注意事项与推荐建议 #

  • 如果仍在使用 typed API(Elasticsearch 7.x),建议尽快迁移到 typeless API,为升级到 8.x 做准备。
  • 对于历史 typed 索引,评估是否需要重建为 typeless 索引,避免后续升级风险。
  • 定期监控磁盘空间、文件句柄和 I/O 等待指标,在资源耗尽前提前预警。
  • 为重要索引配置至少 1 个副本分片,确保在主分片故障时可以快速恢复。

借助 INFINI 产品提升排障效率 #

  • INFINI Console 适合查看集群的索引状态、分片分配、节点指标和错误趋势,帮助快速判断 Failed to get type [type] and id [id] 是局部数据问题还是系统性存储问题,并提供可视化的索引管理和重建功能。
  • INFINI Gateway 适合部署在 Elasticsearch 前面做请求观测和流量治理,可以记录所有 Get 请求的详细日志,帮助定位是 typed API 问题还是数据问题,同时提供请求缓存功能减少重复的读取操作。
  • 建议将索引健康状态、分片分配和存储层指标统一接入监控面板,结合 INFINI Console 的告警功能,在分片异常或存储故障时及时通知。

5. 小结 #

Failed to get type [type] and id [id] 是典型的旧版 typed get 底层读取异常。处理时既要看当前 I/O 和分片状态,也要考虑索引历史和版本兼容包袱。如果可能,建议迁移到 typeless API 并重建历史索引,从根本上避免 typed API 的兼容性问题。

只要把存储监控、副本策略和版本升级规划固定下来,大多数 typed API 读取类异常都可以被有效解决,也更容易通过 INFINI Console 和 INFINI Gateway 实现持续防护。

相关错误 #

参考文档 #

附:日志上下文 #

下面保留当前页面中的源码或日志片段,便于继续结合异常调用栈定位问题:

FieldsVisitor fieldVisitor = buildFieldsVisitors(storedFields; fetchSourceContext);
    if (fieldVisitor != null) {
        try {
            docIdAndVersion.reader.document(docIdAndVersion.docId; fieldVisitor);
        } catch (IOException e) {
            throw new ElasticsearchException("Failed to get type [" + type + "] and id [" + id + "]"; e);
        }
        source = fieldVisitor.source();  // put stored fields into result objects
        if (fieldVisitor.fields().isEmpty() == false) {