一、 基础原理:倒排索引与Lucene

在准备es面试100题及答案时,基础原理是必考项。Elasticsearch 基于 Lucene 构建,理解其底层存储机制至关重要。

1. 什么是倒排索引?

正排索引是文档ID到内容的映射,而倒排索引(Inverted Index)则是内容到文档ID的映射。它由词典(Term Dictionary)和词项列表(Term List)组成。

词典 (Term Dictionary)

存储所有唯一的词项(Term),通常使用 FST (Finite State Transducer) 结构存储,以便快速查找和判断词项是否存在。

词项列表 (Term List)

对于每个词项,记录它出现在哪些文档中,以及出现的频率(TF)和位置(Position)。这支持了短语搜索和模糊搜索。

2. 分词器 (Analyzer) 的作用

在索引文档前,ES 会通过分词器将文本拆解为词项。一个分词器由三部分组成:

  1. 字符过滤器 (Character Filters):处理原始文本,如去除HTML标签。
  2. 分词器 (Tokenizer):将文本流切分为词项数组。
  3. 词项过滤器 (Token Filters):对词项进行修改,如转为小写、同义词替换、停用词过滤。

面试考点:中文环境下,推荐使用 IK 分词器或 Jieba 分词器,默认的标准分词器对中文支持极差,会将每个汉字作为一个词项,导致搜索精度极低。

二、 集群架构:分片与副本

理解 ES 的分布式架构是回答高级面试题的关键。ES 将数据水平切分为多个 分片 (Shard),并通过 副本 (Replica) 提供容错能力。

1. 主分片与副本分片

  • 主分片 (Primary Shard):决定索引的最大容量。写入数据时,通过路由算法(默认 hash(id) % num_primary_shards)确定数据存储在哪个主分片上。
  • 副本分片 (Replica Shard):主分片的拷贝,提供高可用性和读取性能提升。副本分片不能与主分片在同一节点上。
特性 主分片 (Primary) 副本分片 (Replica)
数量 创建索引时固定,后期不可更改 可随时动态调整
功能 存储数据,处理写入请求 故障恢复,处理搜索/获取请求
数据一致性 数据源 最终一致性

2. 集群状态管理

ES 集群中有一个 Master 节点,负责管理集群状态(Cluster State),包括索引的创建、删除,分片的分配等。集群状态会被缓存到每个节点的内存中,以保证读取性能。当 Master 节点宕机时,集群会从其他 Master eligible 节点中选举新的 Master。

三、 性能调优:搜索与写入优化

在实际工作中,ES 的性能调优是高级工程师的核心竞争力。以下是 es面试100题及答案 中关于调优的高频考点。

1. 写入优化

  • 批量写入 (Bulk API):避免单条写入,使用 Bulk API 一次性提交多条请求,减少网络开销。
  • 调整 refresh_interval:默认每秒刷新一次,写入高峰期可调整为 -1 或更大值,减少 Segment 合并压力。
  • 关闭副本:在大量数据导入初期,可将副本数设为 0,导入完成后再恢复。

2. 搜索优化

  • 避免深分页:ES 不支持 from/size 深分页,因为会消耗大量内存。应使用 search_after 或 Scroll API(仅用于导出,不用于实时搜索)。
  • 使用 Filter Context:Filter 查询不参与评分,且结果会被缓存,性能远高于 Query Context。
  • 合理设置 routing:通过指定 routing 参数,将相关请求路由到同一个分片,避免全局搜索。
// 搜索优化示例:使用 search_after 实现高效分页
{
  "size": 10,
  "query": {
    "match": {
      "status": "published"
    }
  },
  "sort": [
    { "date": "desc" },
    { "_id": "asc" }
  ],
  "search_after": [1542259200000, "abc123"]
}

四、 实战避坑:Java Client 与常见问题

除了理论,面试官常会询问实际开发中遇到的问题。以下是 es面试100题及答案 中关于实战经验的总结。

1. 拒绝服务 (OOM) 问题

ES 是基于 JVM 的,内存管理至关重要。常见 OOM 原因包括:

  • JVM Heap 设置过大(建议不超过 32GB),导致 Full GC 时间过长。
  • 聚合查询数据量过大,超出内存限制。
  • 深分页导致大量文档加载到内存。

2. 数据一致性

ES 提供最终一致性。写入时,数据先写入主分片,再异步复制到副本分片。如果副本分片未同步成功,主分片依然返回成功。这保证了写入性能,但可能导致短暂的数据不一致。

解决方案:如果业务强一致性要求高,可设置 wait_for_active_shards=1 或 wait_for_active_shards=all,但这会牺牲写入性能。

五、 高频面试题深度解析 (Top 10)

以下精选了 es面试100题及答案 中最高频的10个问题,涵盖原理、架构与实战。

Q1: 什么是 ES 的 Near Realtime (NRT)?

ES 是近实时的,数据写入后并非立即可搜。默认情况下,ES 每秒自动刷新一次索引(refresh_interval)。可以通过手动调用 _refresh API 来立即刷新,但频繁刷新会影响性能。

Q2: 如何保证 ES 集群的高可用性?

1. 部署至少 3 个 Master eligible 节点,避免脑裂。
2. 每个索引设置副本分片(Replica > 0)。
3. 节点分布在不同的机架或可用区,防止单点故障。

Q3: Segment Merge 是什么?

ES 每次刷新都会产生新的 Segment。随着 Segment 增多,搜索性能下降。后台线程会定期合并小 Segment 为大 Segment,并删除标记删除的文档。合并过程会消耗 CPU 和 I/O 资源,需监控 indices.segments.count。

Q4: 什么是 Translog?

Translog 是事务日志,用于保证数据不丢失。写入数据时,先写 Translog 再写内存 Buffer。默认每 5 秒或 Translog 大小超过 512MB 时刷盘。如果节点宕机,ES 重启后会从 Translog 恢复数据。

Q5: 如何优化 ES 的聚合查询性能?

1. 使用 composite API 处理大规模聚合。
2. 避免在聚合中使用过于宽泛的字段。
3. 使用 aggs_cache 缓存聚合结果。
4. 如果数据量极大,考虑使用 Cardinality 近似去重而非精确去重。