这是《Elasticsearch 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 本章整理 50 道 Elasticsearch 高频面试题。回答建议采用“结论 + 原理 + 边界 + 生产建议”的结构,不要只背名词。
34.1 基础概念
1. Elasticsearch 是什么?
答:Elasticsearch 是基于 Lucene 的分布式搜索与分析引擎,提供文档模型、倒排索引、全文搜索、聚合分析、分片副本和 REST API。它适合搜索、日志检索和近实时分析,不适合作为强事务主存储。
2. Index、Document、Field 是什么关系?
答:Index 是文档集合和配置单元;Document 是一条 JSON 数据;Field 是文档中的字段。Mapping 定义字段类型和分析方式,决定字段如何被索引和聚合。
3. ES 和 MySQL 有什么区别?
答:MySQL 是事务型数据库,擅长强一致、关联和更新;ES 是搜索分析引擎,擅长全文检索、倒排索引、分布式聚合和近实时查询。生产中常见 MySQL 作为事实来源,ES 作为搜索投影。
4. 为什么 ES 是近实时?
答:写入先进入内存缓冲和 translog,refresh 后生成 Segment 才可搜索。默认刷新间隔约 1 秒,所以写入成功和立即可查不是同一个时点。
5. 集群、节点、分片、副本是什么关系?
答:集群由节点组成;索引拆成主分片;每个主分片可以有副本。文档通过 hash(routing) 定位主分片,主分片同步副本。
6. green、yellow、red 分别代表什么?
答:green 表示主副本都正常;yellow 表示主分片正常但至少一个副本未分配;red 表示至少一个主分片不可用。
7. Lucene 和 ES 的分工是什么?
答:Lucene 负责单机索引结构、搜索、评分、段和事务日志等底层能力;ES 在其上实现分布式分片、副本、路由、集群管理、REST API、安全和查询归并。
8. 什么是倒排索引?
答:倒排索引保存 term 到文档列表的映射,并可能带词频、位置和 norm。它让 term、match、phrase 等查询不需要顺序扫描所有文档。
9. 什么是 Doc Values?
答:Doc Values 是按文档到字段值的列式正排结构,主要用于排序、聚合和脚本访问。大多数聚合和排序字段需要启用 doc_values。
10. _source 的作用是什么?
答:_source 保存原始 JSON,用于返回结果、update、reindex、高亮和数据修复。关闭后可以省磁盘,但会失去更新和重建能力。
34.2 Mapping 与分词
11. keyword 和 text 怎么选?
答:text 会分词,适合标题和描述;keyword 不分词,适合 ID、状态、标签、枚举和聚合字段。同一字段可同时配置 text 和 keyword multi-field。
12. dynamic mapping 有什么风险?
答:自动映射可能把 ID 映射成 text、日期映射错格式,或让高基数字段不断扩展 Mapping,增加 cluster state 和内存成本。生产建议 strict 或 false,并评审新字段。
13. 什么是 analyzer?
答:Analyzer 由 Character Filter、Tokenizer 和 Token Filter 组成,负责把文本变成词项。索引和搜索可以使用不同 analyzer。
14. 中文搜索为什么不能只用 standard?
答:standard 对中文偏单字切分,召回噪声大且短语语义弱。常用 IK 等分词器,并结合业务词库、同义词、停用词和自定义词典。
15. 同义词放在索引阶段还是搜索阶段?
答:索引阶段成本低但更新词表要重建索引;搜索阶段可即时更新但查询会扩展更多词项。业务常用搜索阶段,词表特别稳定时可用索引阶段。
16. nested 和 object 有什么区别?
答:object 会拍平字段,无法区分数组内对象边界;nested 为每个对象建立独立索引结构,能正确查询“颜色红色且尺码 XL”。nested 更精确但成本更高。
17. index、doc_values、enabled、store 分别控制什么?
答:index 控制是否能被搜索;doc_values 控制排序聚合正排;enabled 关闭整个对象解析;store 控制字段是否单独存储。默认通常依赖 _source,不必单独 store。
18. 如何避免字段爆炸?
答:使用 dynamic: strict/false、限制 labels 这类对象索引、字段上线评审、拆分业务数据集、用 metadata 管理字段、清理无用字段并重建索引。
19. Mapping 能修改吗?
答:已有字段类型通常不能直接修改,只能新建索引和 reindex。可以新增字段、修改 analyzer 相关设置有限,或使用别名切换。
20. 如何设计搜索商品 Mapping?
答:标题用 text 加 keyword;品牌/类目/状态用 keyword;价格用 scaled_float 或 double;属性用 nested;销量用于排序聚合保留 doc_values;向量字段按模型维度定义 dense_vector。
34.3 查询 DSL
21. query 和 filter 有什么区别?
答:query 计算相关性评分;filter 只判断是否匹配,可缓存。状态、时间、价格、权限等条件应放 filter。
22. match 和 term 的区别?
答:match 会分析查询文本;term 不分析,适合 keyword 精确匹配。对 text 字段用 term 常常搜不到或结果异常。
23. bool 查询各子句的作用?
答:must 参与评分且必须匹配;filter 必须匹配但不评分;should 提供可选加分;must_not 排除且不评分。
24. match_phrase 为什么比 match 贵?
答:match_phrase 需要检查词项位置和顺序,依赖 positions 信息。适合精确短语或加权,不适合无限扩大召回。
25. multi_match 的 best_fields 和 most_fields 区别?
答:best_fields 取匹配最好的字段得分,适合标题优先;most_fields 把多个字段得分合并,适合多信号补充,但可能重复加权。
26. 为什么深分页慢?
答:每个分片必须取 from+size 条候选并维护排序队列,协调节点再归并。from 越大,内存和 CPU 越大。应使用 search after 或 PIT。
27. search after 为什么能优化翻页?
答:它使用上一页排序值作为游标,只取下一页数据,不需要保存跳过的前 N 条。要求排序稳定且不能直接跳页。
28. PIT 是什么?
答:Point In Time 保存一个索引数据视图,让多次 search after 使用一致快照,减少分页期间数据变化导致的重复或遗漏。
29. _score 是怎么来的?
答:默认主要是 BM25,根据词项 IDF、TF、文档长度、字段 boost 和查询组合方式计算。可用 explain 查看具体贡献。
30. 如何排查某个文档排序不理想?
答:先确认 query 和分词,再用 _explain 查看匹配字段、词频、IDF、boost 和 filter 影响,最后区分召回问题、权重问题或业务因子问题。
34.4 写入与性能
31. 写入链路是什么?
答:协调节点路由,主分片校验并写入 Lucene 缓冲和 translog,再同步副本;refresh 使数据可搜,flush 提交 Lucene,merge 清理删除和合并 Segment。
32. refresh、flush、translog 的区别?
答:refresh 生成可搜索 Segment;flush 执行 Lucene commit 并处理 translog;translog 用于崩溃后重放已确认但未提交的变更。
33. 为什么 update 成本高?
答:Lucene Segment 不可变,更新需要读取旧 _source、标记旧文档删除、写入新文档,merge 时再物理清理,容易造成写入放大。
34. Bulk 返回 200 是否代表全部成功?
答:不代表。Bulk 响应里每个 item 可能有 400、429、版本冲突等错误,应用必须逐项检查并只重试失败项。
35. 如何提高写入吞吐?
答:批量写入、合理并发、放宽 refresh、评估 translog durability、减少热点 update、控制分片和 Mapping 复杂度、预留磁盘和页缓存,并让客户端支持退避。
36. 写入 429 怎么处理?
答:先看 write thread pool rejected、磁盘、merge、节点负载和恢复任务;客户端降低并发并指数退避;服务端治理根因,必要时扩容,而不是盲目加大队列。
37. 为什么主分片数不能直接修改?
答:文档路由依赖 hash(routing) % number_of_primary_shards,修改会导致旧文档无法按公式找到。需要新建索引并 reindex。
38. 分片是不是越多越好?
答:不是。分片多能并行但会增加查询扇出、内存句柄、merge 任务、cluster state 和恢复成本。应按单分片大小、查询模式和写入量设计。
39. 什么是查询扇出?
答:一次查询会被发送到涉及索引的每个分片。索引模式越宽、分片越多,协调节点归并和分片执行成本越高。
40. 聚合为什么慢?
答:常见原因是候选文档多、分片多、桶数量大、字段基数高、嵌套聚合深、cardinality/percentile 内存高、text 字段误聚合或缺少预聚合。
34.5 架构与运维
41. terms 聚合为什么可能不精确?
答:每个分片只返回本地 top shard_size,再由协调节点归并,某些全局高频但本地不突出的词项可能被截断。提高 shard_size 只是提高准确性,不是完全保证。
42. cardinality 是精确去重吗?
答:不是。它基于 HyperLogLog++ 近似算法,precision_threshold 越高越准确但内存越大。财务和对账场景应使用精确计算或数仓。
43. 什么是 global ordinals?
答:分片内为唯一词项建立全局编号,加速 keyword terms 等聚合,但首次构建和 Segment 变化后重建有成本,高基数字段可能造成长尾。
44. 磁盘水印是什么?
答:low 阻止新分片分配,high 触发分片迁移,flood_stage 会设置索引 read-only 阻止写入,用于保护节点磁盘。处理顺序是释放空间、恢复分配、再解除 block。
45. 副本能替代备份吗?
答:不能。副本解决节点故障,但误删除、坏数据和逻辑损坏会同步到副本。备份需要 snapshot 并定期恢复演练。
46. 如何安全修改 Mapping?
答:创建新索引、验证 Mapping 和 Analyzer、双写或通过 reindex 迁移、建别名、灰度读、校验数据、切换别名,并保留回滚索引。
47. 零停机索引变更怎么做?
答:使用别名隔离读写,新索引建好后通过 _reindex 或双写追平数据,检查版本和文档数,原子切换别名,观察后保留旧索引用于回滚。
48. 多租户如何隔离?
答:可按索引、索引前缀或集群隔离,并配合租户 ID、DLS、权限、别名、监控和备份策略。大租户应有独立迁移和容量治理方案。
49. ES 集群如何做高可用?
答:至少 3 个 master-eligible 和多个 data 节点,合理副本和 awareness,快照异地备份,Kafka 缓冲写入,滚动升级控制 allocation,并定期故障演练。
50. 如果让你设计商品搜索,怎么开始?
答:先明确 SKU/SPU、搜索指标和排序目标;设计 Mapping 与分词器;实现多路召回和 filter;提供筛选聚合和业务排序;接入点击日志与评测集;最后做别名、监控、降线和容量治理。
34.6 面试表达技巧
回答架构题时建议主动补充:
- 场景和数据规模;
- 写入和查询峰值;
- 分片、副本和保留策略;
- 一致性和幂等方案;
- 性能瓶颈和监控指标;
- 故障时如何降级;
- 方案的取舍和成本。
不要一开口就给参数。参数应来自业务目标和压测数据。
本章小结
面试中最重要的不是背出所有 API,而是能讲清机制、边界和生产取舍。每道题都可以从“是什么、为什么、什么时候不适合、生产怎么做”四个角度扩展。
思考题
- 你最容易讲错的三道题是哪些?
- 哪些问题需要结合自己项目数据规模回答?
- 如何把一次线上故障整理成 3 分钟面试案例?