如何排查Elasticsearch查询耗时超400ms的原因?
Elasticsearch查询耗时过长排查求助
我的搜索查询耗时超过400ms(通过Jaeger追踪),并发请求数约10次,速度过慢,希望帮忙排查原因。

索引基本信息
- 索引包含46000条记录,分为5个分片
Mapping配置
"table_name" : { "type" : "text", "analyzer" : "autocomplete", "search_analyzer" : "standard" }, "table_name_rough" : { "type" : "text", "analyzer" : "autocomplete", "search_analyzer" : "standard" },
查询代码实现
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); BoolQueryBuilder boolQueryBuilderTableName = new BoolQueryBuilder(); boolQueryBuilder.must(QueryBuilders.termQuery("is_deleted", 0)); if (Strings.isNotNullOrEmpty(keyword)) { boolQueryBuilderTableName.should(QueryBuilders.matchPhraseQuery("table_name", keyword)); boolQueryBuilderTableName.should(QueryBuilders.matchPhraseQuery("table_name_rough", keyword)); // table_name 存储带重音的内容,比如 "hôm nay", "tìm kiếm" // table_name_rough 对应不带重音的内容,比如 "hom nay", "tim kiem" boolQueryBuilderTableName.minimumShouldMatch(1); } if (Strings.isNotNullOrEmpty(userId)) { boolQueryBuilder.must(QueryBuilders.termQuery("user_id", String.valueOf(userId))); } boolQueryBuilder.must(boolQueryBuilderTableName); Span spanES = OpenTracerManager.getInstance().buildSpan("query ES").start(); SearchResponse searchResponse = tableElasticRepository.searchElastichByQuery(limit, page, boolQueryBuilder); span.finish();
SearchResponse实现代码
public SearchResponse searchElasticByQuery(int limit, int page, BoolQueryBuilder boolQueryBuilder) throws IOException { sort = "_score"; SearchRequest searchRequest = new SearchRequest(tableIndex); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(boolQueryBuilder); searchSourceBuilder.size(limit); searchSourceBuilder.from(page); searchSourceBuilder.sort(sort, SortOrder.DESC); searchSourceBuilder.minScore(0.001F); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); return searchResponse; }
排查方向建议
- 优化
match_phrase查询:match_phrase需要匹配词项的连续位置,再加上autocomplete分词器会生成大量n-gram词项,会大幅增加计算开销。建议换成match查询配合operator: AND,或者调整autocomplete分词器的n-gram长度范围,减少冗余词项。 - 调整分片数量:46000条数据用5个分片,每个分片仅约9000条数据,分片过多会增加节点协调成本。建议调整为2-3个分片(符合Elasticsearch最佳实践:单分片数据量控制在10GB以内、文档数百万级)。
- 用
filter替代must处理过滤条件:is_deleted和user_id这类过滤条件放到filter子句中,filter结果会被缓存,重复查询时直接复用,减少计算量:boolQueryBuilder.filter(QueryBuilders.termQuery("is_deleted", 0)); if (Strings.isNotNullOrEmpty(userId)) { boolQueryBuilder.filter(QueryBuilders.termQuery("user_id", String.valueOf(userId))); } - 优化分页方式:如果
page值较大,from+size分页会导致ES在每个分片加载大量数据后再排序截断,建议换成search_after分页,避免深度分页的性能损耗。 - 检查节点资源:查看ES节点的CPU、内存、磁盘IO使用率,CPU高负载可能是查询计算密集导致,内存不足会引发磁盘交换,严重拖慢查询。
- 开启查询Profile:在查询中添加
profile:true,查看具体执行环节的耗时分布,定位是分词、匹配还是排序等步骤占用了最多时间:searchSourceBuilder.profile(true);
内容的提问来源于stack exchange,提问作者Quang Minh
相关产品推荐
相关产品推荐

