核心概念

ElasticSearch 的高性能来自于其底层的 Lucene 引擎和分布式架构的深度优化,主要体现在索引结构存储优化查询优化分布式并行四个维度。

一、倒排索引

1. 核心优势

  • O(1) 时间复杂度:通过词(Term)直接定位文档,避免全表扫描
  • 专为文本检索设计:不同于 B+Tree 的精确查询

2. 查询过程

// MySQL 模糊查询(无法使用索引)
SELECT * FROM products WHERE name LIKE '%手机%';  // 全表扫描,O(n)

// ElasticSearch 倒排索引
"手机"  [Doc1, Doc5, Doc10, ...]  // 直接定位,O(1)

二、Segment 架构

1. 不可变的 Segment

  • 索引由多个不可变的 Segment 组成
  • 优势
    • 无需加锁,支持高并发读
    • 易于缓存,提升查询性能
    • 便于后台合并和压缩

2. 近实时搜索(NRT)

写入流程:
Document → In-Memory Buffer → Refresh (1s) → Segment (可搜索)
                            → Translog (持久化) → Flush → Commit
  • Refresh(默认 1s):将内存数据写入 Segment,但未持久化
  • Flush:将 Segment 持久化到磁盘,清空 Translog

3. Segment 合并

  • 后台自动合并小 Segment,减少文件数
  • 清理已删除文档(标记删除),释放空间

三、存储优化

1. FST(Finite State Transducer)

  • 词典存储:高效压缩,支持前缀查询
  • 内存占用小:共享前缀和后缀
传统 Trie 树:
  cat   →  c-a-t
  cats  →  c-a-t-s
  dog   →  d-o-g

FST:通过共享节点和边,减少 50%-90% 内存

2. 倒排列表压缩

FOR(Frame of Reference)编码

// 原始文档 ID 列表
[100, 105, 110, 115, 120]

// 差值编码
[100, +5, +5, +5, +5]  // 节省存储空间

Roaring Bitmap

  • 对大量连续的文档 ID 使用位图压缩
  • 稀疏数据使用数组存储

3. 列式存储(Doc Values)

  • 用于排序、聚合等操作
  • 采用列式存储,压缩效率高
  • 减少内存占用,支持磁盘访问

四、操作系统缓存

1. 文件系统缓存(Page Cache)

  • ES 依赖操作系统的文件缓存
  • 热数据缓存:频繁访问的 Segment 保留在内存
典型内存分配:
JVM Heap:50%(不超过 32GB)
OS Cache:50%(用于文件缓存)

2. 零拷贝(Zero Copy)

  • 利用 mmap 技术,减少数据拷贝
  • 数据直接从磁盘映射到内存

五、分布式并行

1. 分片(Shard)机制

Index → Primary Shard 0 → Replica Shard 0
     → Primary Shard 1 → Replica Shard 1
     → Primary Shard 2 → Replica Shard 2
  • 并行查询:查询分发到各 Shard,并行执行
  • 分片负载均衡:Replica 分担读请求

2. 查询分发流程

Client → Coordinating Node → 各 Shard 并行查询
                           → 汇总结果 → 排序 → 返回

3. 批量操作

// 批量索引(Bulk API)
BulkRequest bulkRequest = new BulkRequest();
for (Document doc : docs) {
    bulkRequest.add(new IndexRequest("products").source(doc));
}
client.bulk(bulkRequest, RequestOptions.DEFAULT);
  • 减少网络开销
  • 批量构建索引,提升吞吐量

六、查询优化

1. Filter Context(过滤上下文)

  • 不计算相关性评分,结果可缓存
  • 适用于精确匹配、范围查询
// Query Context(计算评分)
QueryBuilders.matchQuery("title", "ElasticSearch");

// Filter Context(不计算评分,可缓存)
QueryBuilders.boolQuery()
    .filter(QueryBuilders.termQuery("status", "published"))
    .filter(QueryBuilders.rangeQuery("price").gte(100).lte(500));

2. 查询缓存

  • Node Query Cache:缓存 Filter 查询结果
  • Shard Request Cache:缓存整个查询结果(适用于聚合)

3. 早期终止(Early Termination)

  • Top-N 查询时,不需要遍历所有文档
  • 利用跳表(Skip List)快速跳过不相关文档

七、硬件和配置优化

1. SSD 磁盘

  • 随机读写性能远超 HDD
  • 适合 ES 的 Segment 读取场景

2. 内存配置

# JVM Heap 不超过 32GB(指针压缩阈值)
-Xms16g
-Xmx16g

# 操作系统留足内存用于文件缓存
Total Memory: 64GB
JVM Heap: 16GB → OS Cache: 48GB

3. 线程池优化

# 查询线程池
thread_pool.search.size: CPU 核心数 * 2
thread_pool.search.queue_size: 1000

# 写入线程池
thread_pool.write.size: CPU 核心数

八、实际优化示例

1. 索引设计

{
  "settings": {
    "number_of_shards": 3,       // 根据数据量和节点数调整
    "number_of_replicas": 1,
    "refresh_interval": "5s",    // 降低刷新频率,提升写入性能
    "translog.durability": "async" // 异步刷盘,高吞吐场景
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "status": {
        "type": "keyword",       // 精确匹配,支持聚合
        "doc_values": true       // 支持排序和聚合
      },
      "created_at": {
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss"
      }
    }
  }
}

2. 查询优化

// 低效查询(全文检索 + 评分)
QueryBuilders.matchQuery("content", "ElasticSearch");

// 高效查询(Filter + Query)
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
    .must(QueryBuilders.matchQuery("content", "ElasticSearch"))  // 需要评分
    .filter(QueryBuilders.termQuery("status", "published"))      // 不评分,可缓存
    .filter(QueryBuilders.rangeQuery("views").gte(1000));        // 不评分,可缓存

3. 批量写入优化

// 批量大小:1000-5000 文档
// 刷新频率:降低到 30s 或 -1(手动刷新)
client.indices().putSettings(new PutSettingsRequest("products")
    .settings(Settings.builder().put("refresh_interval", "30s")), 
    RequestOptions.DEFAULT);

// 批量导入数据
BulkRequest bulkRequest = new BulkRequest();
// ... 添加文档
client.bulk(bulkRequest, RequestOptions.DEFAULT);

// 导入完成后手动刷新
client.indices().refresh(new RefreshRequest("products"), RequestOptions.DEFAULT);

总结

ElasticSearch 的高性能来自多方面的优化:

维度 关键技术 性能提升
索引结构 倒排索引 O(1) 词查找
架构设计 Segment + NRT 无锁并发、近实时
存储优化 FST + 压缩算法 内存和磁盘占用减少 50%-90%
系统缓存 OS Page Cache 热数据内存访问
分布式 分片并行 线性扩展
查询优化 Filter Cache 避免重复计算

面试要点

  • 突出倒排索引的核心作用
  • 说明 Segment 不可变带来的高并发优势
  • 提及 FST、压缩算法等存储优化
  • 强调分布式并行查询和 OS 缓存的作用
  • 可结合实际场景说明优化方法(如调整 refresh_interval)