--- title: "多搜索" date: 2026-01-12 lastmod: 2026-01-12 description: "在单个请求中执行多个搜索查询,减少网络往返" tags: ["搜索", "批量查询", "性能优化"] summary: "在单个 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)格式:" --- 在单个 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 } ... ``` #### 头部格式 ```json { "index": "index_name", "search_type": "query_then_fetch", "preference": "_local", "routing": "routing_value", "allow_partial_search_results": true } ``` #### 搜索体格式 ```json { "query": { ... }, "size": 10, "from": 0, "sort": [ ... ], "aggs": { ... } } ``` ## 示例 ### 基本多搜索 ```bash POST /_msearch { "index": "users" } { "query": { "match": { "name": "john" } }, "size": 5 } { "index": "products" } { "query": { "term": { "category": "electronics" } }, "size": 10 } ``` **响应示例:** ```json { "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": [ ... ] } } ] } ``` ### 空头部(使用默认索引) ```bash POST /my_index/_msearch {} { "query": { "match_all": {} }, "size": 10 } {} { "query": { "term": { "status": "active" } }, "size": 5 } ``` ### 每个搜索指定索引 ```bash POST /_msearch { "index": "logs" } { "query": { "match": { "level": "ERROR" } } } { "index": "metrics" } { "query": { "range": { "@timestamp": { "gte": "now-1h" } } } } ``` ### 使用聚合 ```bash POST /sales/_msearch {} { "size": 0, "aggs": { "by_category": { "terms": { "field": "category.keyword" } } } } {} { "size": 0, "aggs": { "by_day": { "date_histogram": { "field": "@timestamp", "calendar_interval": "day" } } } } ``` ### 使用搜索类型 ```bash POST /_msearch?search_type=dfs_query_then_fetch { "index": "products" } { "query": { "match": { "name": "laptop" } } } ``` ### 使用路由 ```bash POST /_msearch { "index": "logs", "routing": "shard1" } { "query": { "term": { "server": "server1" } } } ``` ### 条件过滤 ```bash POST /products/_msearch { "index": "products" } { "query": { "bool": { "filter": { "term": { "in_stock": true } } } } } { "index": "products" } { "post_filter": { "term": { "discounted": false } } } ``` ### 设置超时 ```bash POST /_msearch?timeout=5s { "index": "my_index" } { "query": { "match_all": {} }, "timeout": "2s" } ``` ### 不同排序 ```bash POST /_msearch { "index": "logs" } { "sort": [ { "@timestamp": "desc" } ], "query": { "match_all": {} } } { "index": "products" } { "sort": [ { "price": "asc" } ], "query": { "match_all": {} } } ``` ### 获取特定字段 ```bash POST /_msearch { "_source": ["title", "author"] } { "index": "articles" } { "query": { "match": { "title": "search" } } } ``` ## 请求格式说明 ### NDJSON 格式要求 1. **成对结构**:每个搜索由头部和体组成 2. **换行分隔**:每行之间用换行符 `\n` 分隔 3. **Content-Type**:必须设置为 `application/x-json` 4. **结尾换行**:请求体末尾必须有换行符 ### 格式示例 ``` 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:仪表板多查询 ```bash 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:多索引查询 ```bash POST /_msearch { "index": "logs-2024-*" } { "query": { "term": { "level": "ERROR" } } } { "index": "logs-2025-*" } { "query": { "term": { "level": "ERROR" } } ``` ### 场景 3:不同分页 ```bash 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:聚合查询 ```bash 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` | 分布式查询并获取(已弃用) | ## 注意事项 1. **格式要求**:必须使用 NDJSON 格式 2. **Content-Type**:必须设置为 `application/x-ndjson` 3. **错误处理**:单个搜索失败不影响其他搜索 4. **性能考虑**:大量搜索可能占用较多资源 5. **大小限制**:每个搜索有独立的 from+size 限制