JJava 知识库
JAVA INTERVIEW

高频面试题

ES进阶约 3 分钟

一条商品数据写入 ES 后为什么不能立刻搜到?写入和搜索链路分别发生了什么?

参考回答约 3 分钟 · 口语表达
先说结论

先说结论:写入请求由协调节点根据 routing 计算目标主分片,转发给主分片校验并执行,再并行复制到副本,最后按确认条件响应。搜索则由协调节点向相关分片发起 scatter,分片返回候选文档及排序信息,协调节点全局归并后再 fetch 所需文档内容。

01

我先给结论,再说明它在项目里解决什么问题。串联协调节点、主分片、副本、scatter-gather 和相关性排序。写入请求由协调节点根据 routing 计算目标主分片,转发给主分片校验并执行,再并行复制到副本,最后按确认条件响应。搜索则由协调节点向相关分片发起 scatter,分片返回候选文档及排序信息,协调节点全局归并后再 fetch 所需文档内容。 自定义 routing 可减少查询扇出,但路由选择不均会制造热点,且所有读写必须遵守同一规则。

02

核心机制我会按一次真实执行过程来讲。沿着「协调节点解析请求 → 路由到主分片并复制 → refresh 后建立 Searcher → query phase 收集候选 → fetch phase 拉取文档并合并」观察输入、状态与输出,这些阶段都可以从日志、指标或源码里验证。 协调节点解析请求 任意节点可做协调节点,写请求依据 routing 定位一个主分片,搜索则可能扇出多个分片。

03

实现细节只抓关键入口,不会整段背源码。TransportShardBulkAction:主分片写复制。 QueryPhase/FetchPhase:候选合并与取文档。 我会先确认请求实际走到了哪条路径,再用运行数据验证,不会只看类名或配置猜测。

04

放到生产使用时,我会关注参数和验证数据。逐级增加 size/分片/source 字段,记录 query/fetch 和协调内存。 固定输入和基线 先在没有故障注入的环境执行上述配置,固定数据规模、并发度、运行时版本和预热时间。以「协调节点内存」为主基线,记录值应满足「记录稳态基线」;同时保存 query/fetch phase 时间、协调节点内存,使后续变化能够回到同一时间轴比较。

05

最后补充常见误区和使用边界。请求 size=100000,20 个分片各返回大量候选,协调节点建立巨大优先队列并 fetch 大量 source。改用 searchafter + PIT 流式翻页并限制最大窗口后消除峰值。 忽略协调节点资源:query/fetch phase 时间:限制 size 与返回字段。 方案:更适合的场景:主要收益:代价与边界。 普通 from/size:浅页交互搜索:简单、支持跳页:深页协调内存线性增长。 searchafter + PIT:稳定深度遍历:每页成本稳定、视图一致:需保存排序游标,不能随机跳页。 scroll:离线批量读取旧接口:快照式批量拉取:占用搜索上下文,不适合用户分页。 选型至少带上 文档规模、分片数、字段基数、查询并发和写入速率,并用上面的量化基线验证;