在单个 HTTP 请求中执行多个搜索查询,减少网络往返时间。
API #
GET /_msearch
POST /_msearch
GET /{index}/_msearch
POST /{index}/_msearch
API 的作用 #
Multi Search API 允许在单个请求中执行多个搜索查询,服务器按顺序返回所有结果。
多搜索的优势 #
| 优势 | 描述 |
|---|---|
| 减少网络开销 | 单次请求完成多个搜索 |
| 提高吞吐量 | 批量执行比单独执行更快 |
| 原子性 | 每个搜索独立执行 |
多搜索 vs 单个搜索 #
| 方式 | 请求次数 | 适用场景 |
|---|---|---|
| 单个搜索 | N 次 | 少量不同搜索 |
| 多搜索 | 1 次 | 多个相似搜索 |
API 的参数 #
路由参数 #
| 参数 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
{index} | 字符串 | 否 | 索引名称。支持:单个索引、逗号分隔的多个索引、通配符表达式 |
Query String 参数 #
全局参数 #
| 参数 | 类型 | 是否必填 | 默认值 | 描述 |
|---|---|---|---|---|
max_concurrent_searches | 整数 | 否 | 0 | 最大并发搜索请求数(0 表示无限制) |
pre_filter_shard_size | 整数 | 否 | 128 | 预过滤分片大小 |
max_concurrent_shard_requests | 整数 | 否 | 自动 | 最大并发分片请求数 |
ccs_minimize_roundtrips | 布尔值 | 否 | true | 最小化跨集群搜索往返 |
索引相关 #
| 参数 | 类型 | 是否必填 | 默认值 | 描述 |
|---|---|---|---|---|
search_type | 字符串 | 否 | query_then_fetch | 搜索类型 |
request_cache | 布尔值 | 否 | - | 是否使用请求缓存 |
preference | 字符串 | 否 | - | 首选分片副本:_local、_primary 等 |
routing | 字符串 | 否 | - | 路由值 |
allow_partial_search_results | 布尔值 | 否 | - | 是否允许部分结果 |
expand_wildcards | 枚举值 | 否 | open | 通配符展开方式 |
ignore_unavailable | 布尔值 | 否 | false | 是否忽略不可用索引 |
allow_no_indices | 布尔值 | 否 | false | 是否允许空索引 |
ignore_throttled | 布尔值 | 否 | false | 是否忽略限流索引 |
请求体参数 #
请求体使用 NDJSON(换行分隔的 JSON)格式:
{ 头部1 }
{ 搜索体1 }
{ 头部2 }
{ 搜索体2 }
...
头部格式 #
{
"index": "index_name",
"search_type": "query_then_fetch",
"preference": "_local",
"routing": "routing_value",
"allow_partial_search_results": true
}
搜索体格式 #
{
"query": { ... },
"size": 10,
"from": 0,
"sort": [ ... ],
"aggs": { ... }
}
示例 #
基本多搜索 #
POST /_msearch
{ "index": "users" }
{ "query": { "match": { "name": "john" } }, "size": 5 }
{ "index": "products" }
{ "query": { "term": { "category": "electronics" } }, "size": 10 }
响应示例:
{
"responses": [
{
"took": 5,
"timed_out": false,
"_shards": { ... },
"hits": {
"total": { "value": 1, "relation": "eq" },
"max_score": 0.2876821,
"hits": [ ... ]
}
},
{
"took": 3,
"timed_out": false,
"_shards": { ... },
"hits": {
"total": { "value": 10, "relation": "eq" },
"max_score": 0.876543,
"hits": [ ... ]
}
}
]
}
空头部(使用默认索引) #
POST /my_index/_msearch
{}
{ "query": { "match_all": {} }, "size": 10 }
{}
{ "query": { "term": { "status": "active" } }, "size": 5 }
每个搜索指定索引 #
POST /_msearch
{ "index": "logs" }
{ "query": { "match": { "level": "ERROR" } } }
{ "index": "metrics" }
{ "query": { "range": { "@timestamp": { "gte": "now-1h" } } } }
使用聚合 #
POST /sales/_msearch
{}
{ "size": 0, "aggs": { "by_category": { "terms": { "field": "category.keyword" } } } }
{}
{ "size": 0, "aggs": { "by_day": { "date_histogram": { "field": "@timestamp", "calendar_interval": "day" } } } }
使用搜索类型 #
POST /_msearch?search_type=dfs_query_then_fetch
{ "index": "products" }
{ "query": { "match": { "name": "laptop" } } }
使用路由 #
POST /_msearch
{ "index": "logs", "routing": "shard1" }
{ "query": { "term": { "server": "server1" } } }
条件过滤 #
POST /products/_msearch
{ "index": "products" }
{ "query": { "bool": { "filter": { "term": { "in_stock": true } } } } }
{ "index": "products" }
{ "post_filter": { "term": { "discounted": false } } }
设置超时 #
POST /_msearch?timeout=5s
{ "index": "my_index" }
{ "query": { "match_all": {} }, "timeout": "2s" }
不同排序 #
POST /_msearch
{ "index": "logs" }
{ "sort": [ { "@timestamp": "desc" } ], "query": { "match_all": {} } }
{ "index": "products" }
{ "sort": [ { "price": "asc" } ], "query": { "match_all": {} } }
获取特定字段 #
POST /_msearch
{ "_source": ["title", "author"] }
{ "index": "articles" }
{ "query": { "match": { "title": "search" } } }
请求格式说明 #
NDJSON 格式要求 #
- 成对结构:每个搜索由头部和体组成
- 换行分隔:每行之间用换行符
\n分隔 - Content-Type:必须设置为
application/x-json - 结尾换行:请求体末尾必须有换行符
格式示例 #
POST /_msearch
Content-Type: application/x-ndjson
{ "index": "users" }
{ "query": { "match": { "name": "john" } } }
{ "index": "products" }
{ "query": { "match": { "category": "electronics" } } }
响应字段说明 #
| 字段 | 描述 |
|---|---|
responses | 每个搜索的响应数组 |
responses[].took | 执行时间(毫秒) |
responses[].timed_out | 是否超时 |
responses._shards | 分片信息 |
responses[].hits | 搜索结果 |
使用场景 #
场景 1:仪表板多查询 #
POST /_msearch
{}
{ "size": 5, "query": { "match": { "level": "ERROR" } }, "sort": [ { "@timestamp": "desc" } ] }
{}
{ "size": 0, "query": { "bool": { "filter": { "range": { "@timestamp": { "gte": "now-1d" } } } }, "aggs": { "errors_per_hour": { "date_histogram": { "field": "@timestamp", "calendar_interval": "hour" } } } }
{}
{ "size": 1, "query": { "match": { "message": "critical" } } }
场景 2:多索引查询 #
POST /_msearch
{ "index": "logs-2024-*" }
{ "query": { "term": { "level": "ERROR" } } }
{ "index": "logs-2025-*" }
{ "query": { "term": { "level": "ERROR" } }
场景 3:不同分页 #
POST /products/_msearch
{}
{ "from": 0, "size": 10, "query": { "match": { "category": "electronics" } } }
{}
{ "from": 10, "size": 10, "query": { "match": { "category": "electronics" } } }
{}
{ "from": 20, "size": 10, "query": { "match": { "category": "electronics" } } }
场景 4:聚合查询 #
POST /analytics/_msearch
{}
{ "size": 0, "aggs": { "users": { "cardinality": { "field": "user_id.keyword" } } } }
{}
{ "size": 0, "aggs": { "categories": { "terms": { "field": "category.keyword" } } } }
{}
{ "size": 0, "aggs": { "dates": { "date_histogram": { "field": "date", "calendar_interval": "day" } } } }
搜索类型 #
| 类型 | 描述 |
|---|---|
query_then_fetch | 默认,先查询再获取 |
dfs_query_then_fetch | 先分布式查询再获取(不推荐) |
query_and_fetch | 查询并获取(已弃用) |
dfs_query_and_fetch | 分布式查询并获取(已弃用) |
注意事项 #
- 格式要求:必须使用 NDJSON 格式
- Content-Type:必须设置为
application/x-ndjson - 错误处理:单个搜索失败不影响其他搜索
- 性能考虑:大量搜索可能占用较多资源
- 大小限制:每个搜索有独立的 from+size 限制





