Elasticsearch实战:从索引设计到性能优化的完整指南

📅 2026/7/15 13:36:55 👁️ 阅读次数 📝 编程学习
Elasticsearch实战:从索引设计到性能优化的完整指南

Elasticsearch实战:从索引设计到性能优化的完整指南

大家好,我是迪哥。Elasticsearch 是我们系统的核心搜索组件,从商品搜索到日志分析,从全文检索到聚合分析,它无处不在。今天就聊聊 ES 的索引设计和性能优化经验。

索引设计

分片与副本

{ "settings": { "number_of_shards": 5, "number_of_replicas": 2 } }

映射设计

{ "mappings": { "properties": { "title": { "type": "text", "analyzer": "ik_max_word", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "price": { "type": "float" }, "create_time": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss" }, "tags": { "type": "keyword" } } } }

分词器选择

分词器适用场景特点
standard英文按单词分词
ik_max_word中文细粒度分词
ik_smart中文粗粒度分词
pinyin拼音搜索支持拼音查询

查询优化

避免全表扫描

// ❌ 全表扫描 SearchRequest request = new SearchRequest("orders"); SearchSourceBuilder source = new SearchSourceBuilder(); source.query(QueryBuilders.matchAllQuery()); // ✅ 范围查询 source.query(QueryBuilders.rangeQuery("create_time") .gte("2024-01-01") .lte("2024-01-31"));

使用布尔查询

BoolQueryBuilder boolQuery = QueryBuilders.boolQuery() .must(QueryBuilders.matchQuery("title", "手机")) .filter(QueryBuilders.rangeQuery("price").lte(5000)) .mustNot(QueryBuilders.termQuery("status", "DELETED"));

聚合查询优化

// 使用分片聚合 TermsAggregationBuilder aggregation = AggregationBuilders .terms("by_category") .field("category") .shardSize(100); // 提前终止 aggregation.size(10);

写入优化

Bulk API

BulkRequest bulkRequest = new BulkRequest(); bulkRequest.add(new IndexRequest("orders").id("1").source(document1)); bulkRequest.add(new IndexRequest("orders").id("2").source(document2)); bulkRequest.add(new IndexRequest("orders").id("3").source(document3)); BulkResponse response = client.bulk(bulkRequest, RequestOptions.DEFAULT);

刷新策略

IndexRequest request = new IndexRequest("orders") .id("1") .source(document) .setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);

禁用副本写入

// 初始化时禁用副本,写入完成后恢复 client.indices().putSettings( new PutSettingsRequest("orders") .put("number_of_replicas", 0), RequestOptions.DEFAULT );

性能调优

JVM 调优

# jvm.options -Xms8g -Xmx8g -XX:+UseG1GC -XX:MaxGCPauseMillis=200

索引优化

{ "settings": { "index": { "refresh_interval": "30s", "number_of_replicas": 1, "translog": { "durability": "async", "sync_interval": "5s" } } } }

查询缓存

// 启用分片查询缓存 client.indices().putSettings( new PutSettingsRequest("orders") .put("index.queries.cache.enabled", true), RequestOptions.DEFAULT );

常见问题

问题 1:查询慢

原因:全表扫描、缺少索引、分片数不合理

解决方案

  • 添加合适的索引
  • 优化查询语句
  • 调整分片数

问题 2:写入慢

原因:副本过多、刷新频繁、bulk 大小不合理

解决方案

  • 减少副本数
  • 增大 refresh_interval
  • 调整 bulk 大小

问题 3:内存溢出

原因:JVM 堆内存不足、查询结果过大

解决方案

  • 增大堆内存
  • 使用滚动查询
  • 设置查询大小限制

说到搜索,我家那只叫 Docker 的哈士奇最近学会了"全文搜索"——不管我把零食藏在哪里,它都能精准找到,这搜索能力比我们的 ES 还强 😂

我是迪哥,我们下期再见!