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

适用版本: 7.16-8.9

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

failed to parse More Like This item. neither [id] nor [doc] is specified! 是 Elasticsearch 在执行 more_like_this 查询时抛出的解析异常。该错误表示在构造 More Like This 查询项时,既没有指定 id 也没有指定 doc 参数,而这两者至少需要提供其一,Elasticsearch 才能确定要以哪一篇文档为基准去查找相似内容。

More Like This 查询的核心逻辑是:根据给定的文档(通过 id 从索引中读取,或直接通过 doc 内嵌提供),提取其字段中的关键词,再据此执行相似度搜索。如果两项都缺失,Elasticsearch 无法继续解析查询,便会在 DSL 解析阶段直接抛出 ElasticsearchParseException

常见现象 #

  • 请求返回 HTTP 400 Bad Request,响应体中包含 failed to parse More Like This item 错误信息。
  • 异常类型通常为 ElasticsearchParseException,报错位置会直接指向 more_like_this 查询的 like 数组中的某一项。
  • 如果请求来自应用代码、模板或自动化脚本,该错误会稳定复现,直到查询 DSL 结构被修正。
  • 在 Kibana Dev Tools 或 curl 请求中执行时,错误会立即返回,不会触发任何搜索执行。

典型报错与异常栈 #

{
  "error": {
    "root_cause": [
      {
        "type": "parse_exception",
        "reason": "failed to parse More Like This item. neither [id] nor [doc] is specified!"
      }
    ],
    "type": "parse_exception",
    "reason": "failed to parse More Like This item. neither [id] nor [doc] is specified!"
  },
  "status": 400
}

服务端日志中常见的异常栈片段:

throw new ElasticsearchParseException(
    "failed to parse More Like This item. either [id] or [doc] can be specified; but not both!"
);
}
if (item.id == null && item.doc == null) {
    throw new ElasticsearchParseException(
        "failed to parse More Like This item. neither [id] nor [doc] is specified!"
    );
}

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

More Like This 查询要求每个 like 项必须至少通过 iddoc 中的一种方式指定参考文档。以下是常见原因:

  • like 数组中某一项为空对象:只写了 {} 或者漏填了 id / doc 字段,导致 Elasticsearch 无法识别参考文档。
  • iddoc 同时缺失more_like_this 查询的 like 字段中,每个元素必须包含 id(指定已有文档)或 doc(直接内嵌文档内容),两者都不提供则触发该异常。
  • iddoc 同时指定:根据 Elasticsearch 的校验逻辑,iddoc 是互斥的,不能同时出现,否则会报 either [id] or [doc] can be specified; but not both!
  • 客户端模板渲染错误:使用 SDK 或模板生成 DSL 时,变量未正确替换,导致最终生成的 JSON 中 like 项缺少必要字段。
  • 错误理解 like 参数结构:误以为 like 可以直接传字符串(如 "like": "苹果"),实际上在完整查询结构中 like 应为对象数组,每个对象需包含 iddoc

3. 如何排查这个异常 #

建议按以下步骤定位问题:

  1. 检查完整请求 DSL:将发送给 Elasticsearch 的完整查询体打印出来,重点检查 more_like_this 下的 like 数组结构。
  2. 逐项核对 like 数组:确认数组中每个对象都至少包含 iddoc 之一,且没有同时包含两者。
  3. 在 Kibana Dev Tools 中最小化复现:先构造一个最简的 More Like This 查询,确认语法正确后再逐步加入业务字段。
  4. 对照版本文档:不同版本的 Elasticsearch 对 More Like This 查询的参数要求略有差异,确认当前集群版本对应的文档说明。
  5. 检查客户端代码或模板:如果 DSL 由代码生成,检查变量赋值逻辑,确认 iddoc 字段在序列化时没有被遗漏。

排查时需要注意的问题 #

  • like 参数既可以是字符串数组(简化形式),也可以是对象数组(完整形式)。使用对象形式时,iddoc 是必填的。
  • 如果 like 中混用了字符串和对象两种形式,也可能导致解析异常,建议统一使用一种风格。
  • 使用 doc 方式时,内嵌文档的字段应与目标索引的 mapping 兼容,否则可能触发额外的映射错误。

4. 如何解决这个错误 #

方案一:使用 id 指定参考文档 #

如果参考文档已经存在于索引中,通过 id 指定是最简单的方式:

GET /my-index/_search
{
  "query": {
    "more_like_this": {
      "fields": ["title", "content"],
      "like": [
        {
          "id": "1",
          "index": "my-index",
          "type": "_doc"
        }
      ],
      "min_term_freq": 1,
      "max_query_terms": 12
    }
  }
}

注意:type 参数在 Elasticsearch 7.x 之后已废弃,8.x 中可省略。

方案二:使用 doc 内嵌参考文档 #

如果参考文档不在索引中,或你想直接提供文档内容,使用 doc 方式:

GET /my-index/_search
{
  "query": {
    "more_like_this": {
      "fields": ["title", "content"],
      "like": [
        {
          "doc": {
            "title": "Elasticsearch 查询优化技巧",
            "content": "本文介绍如何优化 Elasticsearch 的查询性能"
          }
        }
      ],
      "min_term_freq": 1,
      "max_query_terms": 12
    }
  }
}

方案三:使用简化字符串形式 #

如果只是简单场景,可以直接用字符串数组(此时不需要 iddoc):

GET /my-index/_search
{
  "query": {
    "more_like_this": {
      "fields": ["title", "content"],
      "like": ["Elasticsearch 查询优化", "相似文档推荐"],
      "min_term_freq": 1,
      "max_query_terms": 12
    }
  }
}

修复步骤总结 #

  1. 确认 like 中每个项的结构:对象形式必须含 iddoc,不能同时含两者。
  2. 选择适合业务场景的方案:id(文档已存在)、doc(动态提供内容)或字符串(简单文本)。
  3. 修正后在测试环境验证,确认 400 错误消失且返回预期结果。

5. 预防措施与最佳实践 #

  • 在客户端代码中封装 More Like This 查询构造器:统一查询构建逻辑,避免散落在各处的手写 DSL 出现结构错误。
  • like 数组做前置校验:在发送请求前,检查每个 like 项是否满足 iddoc 至少存在一个的约束。
  • 使用 Elasticsearch 客户端 SDK 的类型安全 API:如 Java High Level REST Client 或 Elasticsearch Python Client,利用编译期检查减少 DSL 构造错误。
  • 在 CI 流程中加入 DSL 语法检查:对包含 Elasticsearch 查询的配置文件或模板进行静态检查,提前发现结构问题。
  • 建立查询 DSL 的单元测试:对关键搜索场景编写测试,确保查询结构在代码变更后仍然合法。

6. 小结 #

failed to parse More Like This item. neither [id] nor [doc] is specified! 是一个典型的查询 DSL 结构错误,并非运行时故障。修复的核心是理解 more_like_this 查询中 like 参数的三种合法形式(字符串、带 id 的对象、带 doc 的对象),并确保请求体符合对应形式的约束。只要按本文的排查步骤定位缺失字段,再选择合适的修复方案,即可快速解决。

相关错误 #

附:日志上下文 #

throw new ElasticsearchParseException(
    "failed to parse More Like This item. either [id] or [doc] can be specified; but not both!"
);
}
if (item.id == null && item.doc == null) {
    throw new ElasticsearchParseException("failed to parse More Like This item. neither [id] nor [doc] is specified!");
}
return item;
}