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

适用版本: 8.6-8.9

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

a sample requires a minimum of 2 queries; found [1] 是 Elasticsearch 的 Rank Evaluation API(排名评估 API)抛出的参数验证错误。当你使用 Rank Evaluation API 来评估查询排名质量时,必须在请求中提供至少 2 个查询(原始查询和测试查询),如果只提供了 1 个或 0 个查询,就会触发此错误。

常见现象 #

  • Elasticsearch 返回 HTTP 400 Bad Request 状态码,响应体中包含 ParsingException
  • Rank Evaluation API 请求(POST _rank_eval)失败。
  • 在 Elasticsearch 服务端日志中会记录详细的异常信息和查询数量。
  • 如果是通过应用程序或自动化脚本发送请求,会在客户端收到异常响应。
  • 可能导致查询排名评估无法进行,影响搜索质量优化工作。

典型报错与异常栈 #

该异常的典型日志形态如下:

ParsingException: A sample requires a minimum of 2 queries; found [1]
    at org.elasticsearch.search.rank.ProfileRankEvalQueryCollector.parse(ProfileRankEvalQueryCollector.java:...)
    at org.elasticsearch.search.rank.RankEvalQueryCollectorParsers.parse(RankEvalQueryCollectorParsers.java:...)

通过 API 请求的响应通常如下:

{
  "error": {
    "root_cause": [
      {
        "type": "parse_exception",
        "reason": "A sample requires a minimum of 2 queries; found [1]"
      }
    ],
    "type": "search_phase_execution_exception",
    "reason": "all shards failed",
    "failed_shards": [...]
  },
  "status": 400
}

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

Elasticsearch 的 Rank Evaluation API 用于评估查询的排名质量,通过比较原始查询和多组测试查询的排名结果来计算评估指标(如 Precision、Recall、MRR 等)。

源码中的验证逻辑是:

if (queries.size() < 2) {
    throw new ParsingException(source, "A sample requires a minimum of 2 queries; found [{}]", queries.size());
}

这意味着 queries 数组必须至少包含 2 个元素。常见原因包括:

  • 只提供了 1 个查询:如只提供了原始查询,忘记添加测试查询。
  • queries 数组为空:如 {"queries": []},没有提供任何查询。
  • JSON 结构错误queries 字段不是数组,或者是空数组。
  • 变量替换错误:使用模板或变量生成请求时,可能替换为无效值。
  • 复制粘贴错误:从文档或示例复制时,可能遗漏了部分查询。
  • 程序逻辑错误:在代码中动态构造请求时,可能错误地生成了不足 2 个查询。

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

排查步骤 #

建议按以下顺序进行排查:

第一步:获取完整的错误响应和请求体 #

# 重现错误并查看完整响应
curl -X POST "localhost:9200/_rank_eval" -H 'Content-Type: application/json' -d @rank_eval.json 2>&1 | jq .

# 查看 Elasticsearch 日志中的详细错误
tail -n 200 /var/log/elasticsearch/elasticsearch.log | grep -A 20 "A sample requires a minimum of 2 queries"

第二步:检查请求中的 queries 数组 #

# 使用 jq 检查 queries 数组的长度
cat rank_eval.json | jq '.queries | length'

# 查看 queries 数组的内容
cat rank_eval.json | jq '.queries'

第三步:验证正确的 Rank Evaluation API 结构 #

// 错误示例:只有 1 个查询
{
  "queries": [
    {
      "id": "query_1",
      "request": {"query": {"match_all": {}}}
  ]
  // 错误:至少需要 2 个查询
}

// 正确示例:至少 2 个查询
{
  "queries": [
    {
      "id": "original_query",
      "request": {"query": {"match_all": {}}}
    },
    {
      "id": "test_query_1",
      "request": {"query": {"match": {"title": "test"}}}
    },
    {
      "id": "test_query_2",
      "request": {"query": {"match": {"content": "example"}}}
    }
  ],
  "metric": {
    "precision": {"relevant_ratings_threshold": 1}
  }
}

第四步:在测试环境验证 #

# 在测试环境使用合法的 queries 数量进行测试
curl -X POST "localhost:9200/_rank_eval" -H 'Content-Type: application/json' -d '
{
  "queries": [
    {"id": "q1", "request": {"query": {"match_all": {}}},
    {"id": "q2", "request": {"query": {"match": {"title": "test"}}]}
  ],
  "metric": {"precision": {"relevant_ratings_threshold": 1}}
}'

排查时需要注意的问题 #

  • 检查 queries 数组长度:确保至少有 2 个元素。
  • 区分不同的 API:Rank Evaluation API 和其他搜索 API 的参数要求不同。
  • 注意变量替换:如果使用模板,检查替换后的实际值。
  • 查看完整错误信息:错误信息中会显示实际发现的查询数量,这是定位问题的关键。

4. 如何解决这个错误 #

常用修复思路 #

方案一:添加足够的查询数量 #

// 修复前:只有 1 个查询
{
  "queries": [
    {"id": "q1", "request": {"query": {"match_all": {}}}}
  ]
}

// 修复后:至少 2 个查询
{
  "queries": [
    {"id": "q1", "request": {"query": {"match_all": {}}}},
    {"id": "q2", "request": {"query": {"match": {"title": "test"}}}}
  ]
}

方案二:在代码中添加数量校验 #

# Python 示例:在发送请求前校验 queries 数量
def validate_rank_eval_request(request):
    queries = request.get('queries', [])
    if len(queries) < 2:
        raise ValueError(f"Rank Evaluation API requires at least 2 queries, got {len(queries)}")
    return True

# 使用
validate_rank_eval_request(rank_eval_body)

方案三:使用默认值代替动态计算 #

// 如果不确定查询数量,先使用最小合法配置
{
  "queries": [
    {"id": "original", "request": {"query": {"match_all": {}}}},
    {"id": "test", "request": {"query": {"match": {"title": "test"}}}}
  ],
  "metric": {"precision": {"relevant_ratings_threshold": 1}}
}

方案四:修正模板或脚本生成逻辑 #

# Bash 示例:确保生成的 queries 数组至少有 2 个元素
QUERY_COUNT=$1
if [ "$QUERY_COUNT" -lt 2 ]; then
  echo "Warning: Need at least 2 queries, got $QUERY_COUNT"
  exit 1
fi

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

  • 建立 API 参数验证规范:为团队制定 Rank Evaluation API 的参数规范,明确 queries 数组的最小长度要求。
  • 在代码中添加校验:对于动态生成或接收用户输入的参数,在发送请求前进行校验。
  • 使用常量定义常用配置:在代码中定义常用的请求模板,避免重复构造可能出错的结构。
  • 监控 API 错误:通过日志监控及时发现参数验证错误,快速定位和修复。
  • 参考官方文档:在使用 Rank Evaluation API 前,先查阅官方文档,确认参数要求和示例。

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

  • INFINI Console 提供 Rank Evaluation API 的可视化测试和调试功能,可以帮助快速定位 queries 数组数量不足的问题。通过 Console 的查询调试工具,可以在界面上直接构建和测试排名评估请求,查看详细的错误信息。

  • INFINI Gateway 可以拦截和检查发往 Elasticsearch 的 Rank Evaluation API 请求,自动检测并拒绝包含不足 2 个查询的请求。Gateway 还提供请求重写功能,可以在请求到达 Elasticsearch 之前自动修正常见问题。

  • 对于需要频繁使用 Rank Evaluation API 进行搜索质量优化的团队,建议结合 INFINI Console 的请求分析能力和 INFINI Gateway 的请求治理能力,建立从查询构造、验证、执行到监控的完整流程,大幅减少因参数错误导致的异常。

5. 小结 #

a sample requires a minimum of 2 queries; found [1] 是一个典型的参数验证错误,根源在于 Rank Evaluation API 的 queries 数组元素数量不足(< 2)。虽然报错信息直接指向数量问题,但修复思路需要从参数来源入手:无论是硬编码、动态计算还是用户输入,都需要在使用前进行数量校验。

在实际工作中,为避免此类问题,建议在开发阶段就使用 INFINI Console 的查询工具测试 Rank Evaluation API 请求,在代码中建立参数验证机制,并使用 INFINI Gateway 作为防护层来拦截和修正无效的参数。通过规范化和工具化的方式,可以大幅减少此类参数错误的发生。

相关错误 #

参考文档 #

附:日志上下文 #

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

if (queries.size() < 2) {
    throw new ParsingException(source, "A sample requires a minimum of 2 queries; found [{}]", queries.size());
}  

if (hasMissingJoinKeys) {
    throw new ParsingException(missingJoinKeysSource, "A sample must have at least one join key; found none");
}

return new Sample(source, queries);