Skip to content

Elasticsearch 面试题-参考回答

面试官:请简述倒排索引的原理,为什么它查询这么快?

候选人

倒排索引可以理解成一本书后面的“关键词目录”。

正常查数据是拿着文档 ID 去找内容,而倒排索引是反过来的:先把文章、商品标题这些内容分词,然后记录每个词出现在哪些文档里。

比如商品标题里有“苹果手机”,分词后可能有“苹果”“手机”,ES 会记录:

  • “苹果”在哪些商品里出现过
  • “手机”在哪些商品里出现过

用户搜“苹果手机”时,ES 不用一条一条扫商品,而是直接查“苹果”和“手机”对应的文档列表,然后做交集、排序,所以快很多。

它快主要有三个原因:

  1. 不全表扫描,直接通过词找到文档。
  2. 词典索引会用 FST 这类结构放在内存里,查词很快。
  3. 文档 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_noprimary_term 这类机制保证主副本写入顺序,避免旧数据覆盖新数据。

并发更新时,我一般会用乐观锁。更新时带上 if_seq_noif_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 不只按关键词搜,还能按语义搜。

传统搜索里,用户搜“通勤电脑包”,如果商品标题只写了“商务双肩包”,可能搜不到。向量检索会把用户输入和商品文本都转成向量,只要语义接近,就有机会召回。

实现流程一般是这样:

  1. 选一个 embedding 模型,把商品标题、卖点、类目、属性这些文本转成向量。
  2. ES mapping 里加一个 dense_vector 字段,用来存商品向量。
  3. 商品写入或更新时,先生成向量,再把商品基础字段和向量一起写入 ES。
  4. 用户搜索时,也把搜索词转成向量,然后用 kNN 找语义相近的商品。

如果是 ES 8.x,可以用原生 kNN 和 HNSW。如果是 7.17.x,通常会用 dense_vector + script_score,或者结合插件、外部向量库来做。

但我不会只用向量检索。真实项目里一般是“关键词召回 + 向量召回 + 业务排序”一起用。关键词保证精确,向量补长尾和语义,最后再结合销量、价格、库存、转化率做排序。

面试官:你的电商项目中,商品索引有哪些字段?是否都需要分词和建索引?

候选人

商品索引我会按用途来设计,不是所有字段都分词,也不是所有字段都建索引。

核心搜索字段:

  • product_name:商品名,用 text,需要中文分词。
  • selling_point:卖点,用 text,也可以分词。
  • category_name:类目名,可以同时建 textkeyword,搜索和筛选都能用。

筛选和聚合字段:

  • brand_idbrand_namecategory_idshop_idstatus:用 keyword,不分词,用来过滤和聚合。
  • sku_idspu_id:用 keyword,作为精确匹配和文档 ID。

排序和范围字段:

  • pricesale_countstockcomment_countcreated_time:用数值或日期类型,不分词,用于范围查询和排序。

展示字段:

  • image_urlsku_propertiesdetail_url:只用于结果展示,不参与搜索的话可以设置 index: false,减少索引体积和写入压力。

如果做向量检索,还会加:

  • product_vector:类型是 dense_vector,存商品语义向量。

整体原则就是:要搜索的字段用 text,要精确过滤的字段用 keyword,只展示不查询的字段不建索引。

面试官:ES + 向量化在真实电商中怎么用?需要全面考虑哪些点?

候选人

真实电商里,ES + 向量化最常见的价值是解决“用户说法”和“商品说法”不一致的问题。

比如用户搜:

  • “适合上班背的轻薄电脑包”
  • “送女朋友的生日礼物”
  • “不粘锅但不要太重”

这些词不一定直接出现在商品标题里。传统关键词搜索可能召回少,甚至搜不到。向量检索可以理解用户意图,把语义接近的商品召回出来。

我会把它落在几个场景里:

  1. 搜索召回增强:关键词搜不到或召回太少时,用向量补充结果。
  2. 长尾搜索:用户输入很口语化、很长,比如“夏天穿不闷脚的鞋”。
  3. 相似商品推荐:看了某个商品后,用商品向量找相似款、平替款。
  4. 图文混合搜索:如果有图片向量能力,可以支持“拍照找同款”。
  5. 个性化排序:用户兴趣也可以向量化,但一般只作为排序特征之一。

真正落地时,我会重点考虑这些点:

第一,向量内容从哪里来。商品标题太短可能不够,要把标题、类目、品牌、核心属性、卖点组合起来生成 embedding。但价格、库存、上下架状态这种结构化信息不能混进向量里,还是要用 ES 字段过滤。

第二,不能只靠向量。向量能理解语义,但有时不够精确。比如用户搜“苹果手机壳”,不能召回苹果水果。所以要做混合检索:关键词召回保证准确,向量召回补语义,再做融合排序。

第三,过滤条件要前置。电商搜索一定要考虑上下架、库存、店铺、类目、价格区间、配送区域。如果向量召回了一堆下架商品,体验就很差。

第四,排序要结合业务。最终排序不能只看向量相似度,还要看关键词匹配度、销量、点击率、转化率、库存、价格、广告规则和风控规则。

第五,更新成本要算清楚。商品标题、类目、属性变了,向量也要重新生成。大促期间商品更新很多,embedding 接口、消息队列、ES 写入都要能扛住。

第六,性能和成本要压住。向量维度越高,索引越大,查询越慢。HNSW 的参数、召回数量、分片数量、机器内存都要压测,不能只在测试环境看效果。

第七,要有评估指标。不能只说“感觉更智能”,要看无结果率、点击率、转化率、搜索延迟、召回准确率,以及用户投诉有没有下降。

所以我会把 ES + 向量化定位成“搜索召回增强能力”,而不是替代原来的 ES 搜索。真实电商里最稳的方案是:结构化过滤 + 关键词检索 + 向量召回 + 业务重排。