Elasticsearch 面试题-参考回答
面试官:请简述倒排索引的原理,为什么它查询这么快?
候选人:
倒排索引可以理解成一本书后面的“关键词目录”。
正常查数据是拿着文档 ID 去找内容,而倒排索引是反过来的:先把文章、商品标题这些内容分词,然后记录每个词出现在哪些文档里。
比如商品标题里有“苹果手机”,分词后可能有“苹果”“手机”,ES 会记录:
- “苹果”在哪些商品里出现过
- “手机”在哪些商品里出现过
用户搜“苹果手机”时,ES 不用一条一条扫商品,而是直接查“苹果”和“手机”对应的文档列表,然后做交集、排序,所以快很多。
它快主要有三个原因:
- 不全表扫描,直接通过词找到文档。
- 词典索引会用 FST 这类结构放在内存里,查词很快。
- 文档 ID 列表是有序、压缩存储的,做交集时还能用跳表快速跳过无关数据。
所以我一般会总结成一句话:倒排索引就是“用词找文档”,牺牲一些存储空间,换来非常快的搜索速度。
面试官:你项目中使用的 Elasticsearch 版本是哪个?
候选人:
我们项目里用的是 Elasticsearch 7.17.x。
选择这个版本主要是因为它是 7.x 的长期维护版本,比较稳定,生产上用的人也多。
7.x 之后有几个变化我会重点关注:
- 一个索引只保留一个 Type,Mapping 更简单,也减少字段冲突。
- 集群协调机制比老版本更稳定,不需要再手动依赖
discovery.zen.minimum_master_nodes来防脑裂。- 对中文搜索、聚合、日志检索、电商商品搜索这些场景都比较成熟。
如果项目是 8.x,我会补充一句:8.x 对安全能力和向量检索支持更完善,比如原生 kNN 和 HNSW 更好用。
面试官:Elasticsearch 的集群架构是怎样的?
候选人:
ES 集群我一般用三个词来解释:节点、分片、副本。
第一个是节点。一个 ES 进程就是一个节点。生产里通常会区分角色:
- master 节点:负责管理集群,比如选主、维护索引元数据、分配分片。
- data 节点:真正存数据,也负责查询和聚合。
- coordinating 节点:接收请求、转发到各个分片、最后合并结果。
第二个是分片。一个索引的数据可能很大,单机放不下,所以 ES 会把一个索引拆成多个主分片,分散到不同机器上。这样既能扩容,也能并行查询。
第三个是副本。副本就是主分片的备份。它有两个作用:一个是机器挂了不丢数据,另一个是读请求多的时候可以帮主分片分担读压力。
所以 ES 的核心思路就是:数据用分片打散,服务用副本兜底,查询时多台机器一起干活。
面试官:如何优化 Elasticsearch 的查询性能?
候选人:
我会先看查询语句,再看索引设计,最后再看集群资源。
第一,查询语句上:
- 不需要算相关性的条件放到
filter里,比如状态、分类、时间范围。- 只返回需要的字段,不要每次都把完整
_source拉回来。- 避免深分页,
from + size翻得越深越慢,大数据翻页用search_after或 PIT。- 少用前置通配符,比如
*手机,这种会扫很多词条。第二,索引设计上:
- 分片不是越多越好,一般让单个分片控制在几十 GB 以内。
- 字段类型要准确,精确匹配用
keyword,全文搜索用text,价格销量用数值类型。- 对实时性要求不高的场景,可以适当调大
refresh_interval,减少频繁刷新带来的开销。- 如果业务天然按租户、店铺、用户分区,可以用 routing 缩小查询分片范围。
第三,集群资源上:
- 磁盘尽量用 SSD。
- JVM 堆内存不要盲目加太大,通常不超过机器内存的一半,并且尽量不超过 32GB。
- 慢查询要看 slowlog 和 profile,不能只凭感觉优化。
一句话概括就是:少查数据、少算分、少跨分片、让字段类型和查询方式匹配。
面试官:什么是脑裂问题?如何避免?
候选人:
脑裂就是集群因为网络问题分成了两边,两边都以为自己有 master。
这样会很危险,因为两个 master 都可能修改集群元数据,最后导致分片状态混乱,严重时会出现数据不一致。
在 ES 6.x 及以前,主要靠
discovery.zen.minimum_master_nodes控制,公式一般是:
master 候选节点数 / 2 + 1比如 3 个 master 候选节点,就至少要 2 个节点同意才能选主。
ES 7.x 以后集群协调机制重做了,选主协议本身会保证多数派原则。首次启动时配置好
cluster.initial_master_nodes,后面不要把它当成日常配置反复改。生产上我会建议用 3 个专用 master 节点,master 节点不要承担大量查询和写入,避免因为 GC 或 CPU 打满影响集群稳定性。
面试官:Elasticsearch 如何保证数据一致性?
候选人:
ES 的一致性要分几个角度说,不能简单说它是强一致或者最终一致。
写入时,请求会先到主分片,主分片写成功后再同步到副本分片。ES 会通过
seq_no和primary_term这类机制保证主副本写入顺序,避免旧数据覆盖新数据。并发更新时,我一般会用乐观锁。更新时带上
if_seq_no和if_primary_term,如果中间有人改过这条数据,ES 会返回冲突,业务再决定重试还是提示失败。读取上要注意,ES 搜索是近实时的。写入成功后,不一定立刻能被搜索到,默认要等下一次 refresh,大概 1 秒左右。但如果是根据 ID 做
GET,通常可以读到最新数据。所以面试里我会这样总结:ES 适合搜索场景,不适合当强一致事务数据库用。核心数据还是放 MySQL,ES 做搜索和查询加速。
面试官:面对亿级数据,如何设计索引和优化?
候选人:
亿级数据我不会只想着“加机器”,会先把索引拆分策略定好。
第一,按业务维度拆索引。日志、订单这类有明显时间属性的数据,可以按天或按月建索引,比如
order-2026-06。查询时带上时间范围,就不用扫所有历史数据。第二,控制分片大小。分片太大会查询慢、恢复慢;分片太多又会占资源。一般我会让单个分片保持在 30GB 到 50GB 左右,再根据数据量和节点数算主分片数量。
第三,冷热分离。最近的数据放热节点,用 SSD,承接高频读写;历史数据放温节点或冷节点,降低成本。可以用 ILM 做生命周期管理。
第四,查询要限制范围。能按时间、租户、店铺、分类过滤就先过滤。聚合时也要控制 bucket 数量,大聚合可以用
composite分页,避免一次性把内存打爆。最后,我会配合 alias 做索引切换。比如重建索引时先写到新索引,验证没问题后再切别名,这样对线上用户是无感的。
面试官:数据量特别大,全量同步和增量同步怎么实现?怎么优化?
候选人:
我们一般会把同步分成全量和增量两条链路。
全量同步通常是从 MySQL 按主键范围分页拉数据,然后用 Bulk 批量写入 ES。这里不建议用很深的 offset 分页,数据越大越慢,最好用
id > lastId这种方式。全量导入时可以做几个优化:
- 每批控制在合适大小,比如几千条或 5MB 到 15MB。
- 写入新索引时可以临时调大
refresh_interval,甚至先关闭自动 refresh。- 如果是离线重建的新索引,可以先把副本设为 0,导完再恢复副本。
- 导完后校验数量和关键字段,再用 alias 切换。
增量同步一般用 Canal 监听 MySQL binlog,再经过 Kafka,最后由消费者写 ES。
增量里最重要的是防丢、防重、防乱序:
- ES 文档 ID 使用 MySQL 主键,重复消费也只是覆盖,不会插出两条。
- 删除操作也要同步,不能只同步新增和修改。
- 消费失败要有重试和死信队列。
- 如果有乱序风险,可以用版本号或更新时间做保护,避免旧消息覆盖新消息。
一句话就是:全量负责打底,增量负责追平,最后通过校验和 alias 做无停机切换。
面试官:ES + 向量化检索怎么实现?
候选人:
ES + 向量化,本质是让 ES 不只按关键词搜,还能按语义搜。
传统搜索里,用户搜“通勤电脑包”,如果商品标题只写了“商务双肩包”,可能搜不到。向量检索会把用户输入和商品文本都转成向量,只要语义接近,就有机会召回。
实现流程一般是这样:
- 选一个 embedding 模型,把商品标题、卖点、类目、属性这些文本转成向量。
- ES mapping 里加一个
dense_vector字段,用来存商品向量。- 商品写入或更新时,先生成向量,再把商品基础字段和向量一起写入 ES。
- 用户搜索时,也把搜索词转成向量,然后用 kNN 找语义相近的商品。
如果是 ES 8.x,可以用原生 kNN 和 HNSW。如果是 7.17.x,通常会用
dense_vector + script_score,或者结合插件、外部向量库来做。但我不会只用向量检索。真实项目里一般是“关键词召回 + 向量召回 + 业务排序”一起用。关键词保证精确,向量补长尾和语义,最后再结合销量、价格、库存、转化率做排序。
面试官:你的电商项目中,商品索引有哪些字段?是否都需要分词和建索引?
候选人:
商品索引我会按用途来设计,不是所有字段都分词,也不是所有字段都建索引。
核心搜索字段:
product_name:商品名,用text,需要中文分词。selling_point:卖点,用text,也可以分词。category_name:类目名,可以同时建text和keyword,搜索和筛选都能用。筛选和聚合字段:
brand_id、brand_name、category_id、shop_id、status:用keyword,不分词,用来过滤和聚合。sku_id、spu_id:用keyword,作为精确匹配和文档 ID。排序和范围字段:
price、sale_count、stock、comment_count、created_time:用数值或日期类型,不分词,用于范围查询和排序。展示字段:
image_url、sku_properties、detail_url:只用于结果展示,不参与搜索的话可以设置index: false,减少索引体积和写入压力。如果做向量检索,还会加:
product_vector:类型是dense_vector,存商品语义向量。整体原则就是:要搜索的字段用
text,要精确过滤的字段用keyword,只展示不查询的字段不建索引。
面试官:ES + 向量化在真实电商中怎么用?需要全面考虑哪些点?
候选人:
真实电商里,ES + 向量化最常见的价值是解决“用户说法”和“商品说法”不一致的问题。
比如用户搜:
- “适合上班背的轻薄电脑包”
- “送女朋友的生日礼物”
- “不粘锅但不要太重”
这些词不一定直接出现在商品标题里。传统关键词搜索可能召回少,甚至搜不到。向量检索可以理解用户意图,把语义接近的商品召回出来。
我会把它落在几个场景里:
- 搜索召回增强:关键词搜不到或召回太少时,用向量补充结果。
- 长尾搜索:用户输入很口语化、很长,比如“夏天穿不闷脚的鞋”。
- 相似商品推荐:看了某个商品后,用商品向量找相似款、平替款。
- 图文混合搜索:如果有图片向量能力,可以支持“拍照找同款”。
- 个性化排序:用户兴趣也可以向量化,但一般只作为排序特征之一。
真正落地时,我会重点考虑这些点:
第一,向量内容从哪里来。商品标题太短可能不够,要把标题、类目、品牌、核心属性、卖点组合起来生成 embedding。但价格、库存、上下架状态这种结构化信息不能混进向量里,还是要用 ES 字段过滤。
第二,不能只靠向量。向量能理解语义,但有时不够精确。比如用户搜“苹果手机壳”,不能召回苹果水果。所以要做混合检索:关键词召回保证准确,向量召回补语义,再做融合排序。
第三,过滤条件要前置。电商搜索一定要考虑上下架、库存、店铺、类目、价格区间、配送区域。如果向量召回了一堆下架商品,体验就很差。
第四,排序要结合业务。最终排序不能只看向量相似度,还要看关键词匹配度、销量、点击率、转化率、库存、价格、广告规则和风控规则。
第五,更新成本要算清楚。商品标题、类目、属性变了,向量也要重新生成。大促期间商品更新很多,embedding 接口、消息队列、ES 写入都要能扛住。
第六,性能和成本要压住。向量维度越高,索引越大,查询越慢。HNSW 的参数、召回数量、分片数量、机器内存都要压测,不能只在测试环境看效果。
第七,要有评估指标。不能只说“感觉更智能”,要看无结果率、点击率、转化率、搜索延迟、召回准确率,以及用户投诉有没有下降。
所以我会把 ES + 向量化定位成“搜索召回增强能力”,而不是替代原来的 ES 搜索。真实电商里最稳的方案是:结构化过滤 + 关键词检索 + 向量召回 + 业务重排。