--- id: backend.elasticsearch.interview title: Elasticsearch 面试题 type: interview domain: backend stack: [elasticsearch] tags: [Elasticsearch, 倒排索引, 混合检索, 面试] level: intermediate related: [backend.elasticsearch.search-hybrid] week: [14, 16] --- # Elasticsearch 面试题 ## 基础 ### 【基础】什么是倒排索引? **参考答案**:从“词”到“包含该词的文档列表(及位置、词频)”的映射。写入时对文本分词建立倒排表,查询时分词后查表求交并、算分,所以全文检索快。 **追问**:为什么 ES 写入后不能立即搜到?→ 近实时:写入先进内存缓冲,`refresh`(默认约 1 秒)后生成新的段才可搜索;可以 `refresh=wait_for` 但会影响写入性能。 ### 【基础】`text` 和 `keyword` 的区别? **参考答案**:`text` 会分词,用于全文检索;`keyword` 不分词,用于精确匹配、过滤、排序和聚合。同一字段可以用多字段(`fields`)同时建两种。 **追问**:对 `text` 字段做 `term` 查询会怎样?→ 往往查不到,因为存储的是分词后的词项,而 `term` 查询不分词。 ### 【基础】`must` 和 `filter` 的区别? **参考答案**:都要求匹配;`must` 参与相关性算分,`filter` 不算分并且可以被缓存,适合租户、权限、状态、时间范围等条件。 **追问**:权限条件应该放哪里?→ `filter`,并且在向量检索中也要通过 `knn.filter` 传入。 ## 进阶 ### 【进阶】混合检索怎么做?为什么常用 RRF? **参考答案**:关键词(BM25)和向量(kNN)分别召回,再融合。BM25 分数无上限、与查询相关,向量相似度在固定区间,直接加权需要归一化且不稳定;RRF 只用名次 `1/(k+rank)` 求和,简单稳健。融合后再用重排模型精排。 **追问**:服务端 RRF 和应用层 RRF 怎么选?→ 服务端少一次往返、写法简洁,但受版本和许可证限制;应用层灵活、可以融合来自不同系统(例如 ES + pgvector)的结果。 ### 【进阶】映射需要修改怎么办? **参考答案**:已有字段的类型和分词器不能修改。新建索引(新映射)→ `_reindex` 或从数据源重新导入 → 追平增量 → 校验 → 原子切换别名 → 保留旧索引以便回滚。 **追问**:重建期间的增量写入怎么处理?→ 双写到新旧索引,或者重建完成后按时间戳 / 版本号补齐差异再切换。 ### 【进阶】中文分词怎么做? **参考答案**:常用 IK 插件:写入用细粒度(`ik_max_word`),查询用粗粒度(`ik_smart`);维护业务词典和同义词;插件版本要与 ES 一致。内置 `cjk` 分析器按二元切分,可以作为没有插件时的方案。 **追问**:词典更新后要做什么?→ 新写入的数据按新词典分词,已有数据需要重建索引才会生效。 ## 场景题 ### 【场景题】RAG 知识库对型号、错误码检索不准,怎么改? **参考答案**:引入关键词检索与向量检索混合(ES BM25 + kNN,RRF 融合 + 重排);业务词典保证型号不被切碎;权限作为 filter;同步链路保证数据新鲜;用标注集评估召回率。详见[知识库混合检索场景](scenarios/kb-search-sync.md)。 **追问**:怎么证明改进有效?→ 固定标注集,对比改动前后的召回率@K、MRR 以及最终回答的正确率。 ### 【场景题】数据库中的数据怎么可靠地同步到 ES? **参考答案**:常用方案:业务事务内写 outbox 表 → 投递到消息队列 → 幂等消费者写 ES(数据库主键作为 `_id`、带版本号防止旧数据覆盖新数据);或者用 CDC(读取数据库日志,如 Debezium / MongoDB 变更流)。失败重试 + 死信 + 定期对账。 **追问**:消息乱序导致旧版本覆盖新版本怎么办?→ 使用外部版本号(`version_type=external`)或写入前比较更新时间,只接受更新的版本。