在 OpenSearch 中搜索查询的生命周期
抱歉,我只能看到您提供的来源链接,而没有看到需要翻译的正文内容。请您把要翻译的文本粘贴在这里,我会帮您翻译成简体中文,并保留原始的格式和代码块。
概览
A search request typically looks like:
GET /my-index/_search
Content-Type: application/json
{
"query": { "match": { "title": "opensearch" } },
"size": 10,
"from": 0,
"_source": true
}
客户端可以是 curl 到 Python SDK 等任何工具;传输格式始终是基于 HTTP 的 JSON。
HTTP 请求和协调节点
- HTTP 服务器 – OpenSearch 运行一个轻量级的 HTTP 服务器,用于解析请求。
- 协调节点 – 接收请求的节点会成为协调节点。集群中的任何节点都可以充当协调者;它 不需要 存储数据。
分片与路由
- 数据存储在 shards(分片)中——即分布在集群中的 Lucene 索引。
- 每个文档根据路由值(默认是文档
_id)被分配到一个 primary shard(主分片)。路由公式为:
hash(routing) % number_of_primary_shards
- 协调节点运行此哈希函数,以确定哪些主分片负责处理该查询。
- 对于单个索引上的简单词项查询,协调节点可能需要联系该索引的 all primary shards(所有主分片)。提供特定的路由值可以显著减少需要查询的分片数量,从而降低延迟。
分片上的查询执行
一旦确定了负责的分片,协调节点会将查询转发给分片节点(这些节点可能是同一台物理机器,也可能是不同的机器)。每个分片在本地针对其 Lucene 段执行查询。
段搜索
- Lucene 将数据存储在 不可变段 中。在查询阶段,每个段会被独立搜索。
- OpenSearch 可以在单个分片内部并行搜索段——这项功能称为 concurrent segment search(在 3.0 版中引入)。引擎会根据 CPU 核心数和段大小自动决定创建多少个 slice。
评分 (BM25)
- 对于每个匹配的文档,Lucene 使用 BM25 算法计算相关性得分。
- 关键参数:词项频率、逆文档频率以及长度归一化因子
b(默认值 0.75)。 - 每个分片返回 top‑k(默认 10)文档及其得分。
获取阶段
查询阶段只返回文档 ID 和得分。如果客户端请求了 _source 字段(大多数情况下都会如此),则会执行第二轮称为 fetch phase(获取阶段)的操作:
- 协调节点向每个分片请求所选文档的完整源数据。
- 分片从 Lucene 的存储字段中检索已存储的
_source并返回。
由于获取阶段可能会在网络上传输更大的负载,OpenSearch 会尽量保持获取的文档数量较少。分页(from/size)和 stored_fields 过滤器是重要的性能调节手段。
合并结果
在从每个分片收到 top‑k 结果后,协调节点:
- 合并 它们为一个单一的排序列表。
- 重新应用全局的
size和from参数。 - 根据每个分片返回的 BM25 分数对合并后的集合进行排序。
- 应用查询中指定的任何自定义排序规则。
最终的合并列表会被格式化为 JSON 响应并返回给客户端。
近实时索引
- 新文档首先写入 内存缓冲区 并追加到 translog 以确保持久性。
- 每秒(默认
index.refresh_interval),缓冲区会刷新到一个新的 Lucene 段,使新索引的文档可被搜索。 - 这导致索引与在搜索结果中可见之间通常只有 < 1‑秒延迟。
常见问题与缓解措施
| 问题 | 产生原因 | 缓解措施 |
|---|---|---|
| 查询延迟慢 | 查询的分片过多,段数量过高 | 使用路由,配置 index.routing_partition_size,强制合并以减少段数 |
| CPU 使用率高 | 大分片上的并发段搜索 | 调整 search.max_concurrent_shard_requests 和 search.max_concurrent_segments |
| 结果陈旧 | 刷新间隔过大,无法满足实时需求 | 在热索引上降低 index.refresh_interval |
| 大负载 | 为大量文档获取完整的 _source | 使用 stored_fields 或 docvalue_fields,限制 size |
结论
在 OpenSearch 中,搜索查询不仅仅是一次简单的 HTTP 调用。它涉及路由、并行分片执行、评分、可选的获取以及将所有结果拼接在一起的最终合并步骤。了解每个阶段有助于你设计更好的模式、调优性能,并避免常见的陷阱,例如不必要的分片扫描或过长的刷新间隔。通过可视化查询的整个过程,你可以更有信心诊断延迟问题,选择合适的索引策略,并充分利用 OpenSearch 强大的插件和分析生态系统。