如果没有kibana管理台页面工具,还可以用postman!!!
_search不带条件查询
curl --location --request GET 'http://ip:9200/xxx-gift_pack_record202409/_search' \ --header 'Authorization: Basic ZWxhc3RpYzpIaWhvbm9yQG1hcmtldDFuZw=='_search带条件查询
curl --location --request GET 'http://ip:9200/xxx-t_prize_grant_record202409/_search' \ --header 'Authorization: Basic ZWxhc3RpYzpIaWhvbm9yQG1hcmtldDFuZw==' \ --header 'Content-Type: application/json' \ --data-raw '{ "from": 0, "size": 15, "query": { "bool": { "filter": [ {"term": {"prize_type": {"value": 8, "boost": 1.0}}}, {"range": {"reward_time": {"from": "2024-09-01 00:00:00", "to": "2026-09-30 23:59:59", "include_lower": true, "include_upper": true, "boost": 1.0}}}, {"term": {"es_delete_flag": {"value": "false", "boost": 1.0}}} ], "adjust_pure_negative": true, "boost": 1.0 } }, "sort": [ {"reward_time": {"order": "desc"}}, {"grant_id": {"order": "desc"}} ], "track_total_hits": 2147483647 }'_count查询
curl --location --request GET 'http://ip:9200/xxx-t_prize_grant_record202409/_count' \ --header 'Authorization: Basic ZWxhc3RpYzpIaWhvbm9yQG1hcmtldDFuZw==' \ --header 'Content-Type: application/json' \ --data-raw '{ "query": { "bool": { "filter": [ {"term": {"prize_type": {"value": 8, "boost": 1.0}}}, {"range": {"reward_time": {"from": "2024-09-01 00:00:00", "to": "2026-09-30 23:59:59", "include_lower": true, "include_upper": true, "boost": 1.0}}}, {"term": {"es_delete_flag": {"value": "false", "boost": 1.0}}} ], "adjust_pure_negative": true, "boost": 1.0 } } }'profile分析
curl --location --request GET 'http://ip:9200/xxx-t_prize_grant_record202409/_search' \ --header 'Authorization: Basic ZWxhc3RpYzpIaWhvbm9yQG1hcmtldDFuZw==' \ --header 'Content-Type: application/json' \ --data-raw '{ "profile": true, "from": 0, "size": 15, "query": { "bool": { "filter": [ {"term": {"prize_type": {"value": 8, "boost": 1.0}}}, {"range": {"reward_time": {"from": "2024-09-01 00:00:00", "to": "2026-09-30 23:59:59", "include_lower": true, "include_upper": true, "boost": 1.0}}}, {"term": {"es_delete_flag": {"value": "false", "boost": 1.0}}} ], "adjust_pure_negative": true, "boost": 1.0 } }, "sort": [ {"reward_time": {"order": "desc"}}, {"grant_id": {"order": "desc"}} ], "track_total_hits": 2147483647 }'在查询里加上 "profile": true
explain分析
curl --location --request GET 'http://ip:9200/xxx-t_prize_grant_record202409/_search' \ --header 'Authorization: Basic ZWxhc3RpYzpIaWhvbm9yQG1hcmtldDFuZw==' \ --header 'Content-Type: application/json' \ --data-raw '{ "explain": true, "from": 0, "size": 15, "query": { "bool": { "filter": [ { "term": { "prize_type": { "value": 8, "boost": 1.0 } } }, { "range": { "reward_time": { "from": "2024-09-01 00:00:00", "to": "2026-09-30 23:59:59", "include_lower": true, "include_upper": true, "boost": 1.0 } } }, { "term": { "es_delete_flag": { "value": "false", "boost": 1.0 } } } ], "adjust_pure_negative": true, "boost": 1.0 } }, "sort": [ { "reward_time": { "order": "desc" } }, { "grant_id": { "order": "desc" } } ], "track_total_hits": 2147483647 }'在查询里加上 "explain": true
📊 Elasticsearch 的 Explain 和 Profile 功能详解
🔍Explain(解释查询)
作用:解释为什么某个文档匹配或不匹配查询,显示评分计算过程。
使用场景:
- 调试相关性评分问题
- 理解查询匹配逻辑
- 优化查询性能
使用方法:
# 方式1:使用 _explain 端点 GET /index_name/_explain/doc_id { "query": { "match": { "field": "search term" } } } # 方式2:在 _search 中添加 explain 参数 GET /index_name/_search { "explain": true, "query": { "match": { "field": "search term" } } }返回信息包含:
value:匹配得分description:评分描述details:详细的评分计算过程matched:是否匹配
⚡Profile(性能分析)
作用:详细分析查询执行过程,识别性能瓶颈。
使用场景:
- 优化复杂查询性能
- 识别慢查询原因
- 分析聚合操作性能
使用方法:
GET /index_name/_search { "profile": true, "query": { "match": { "field": "search term" } } }返回信息包含:
查询阶段(Query Phase)
query:查询执行详情rewrite_time:查询重写时间collectors:结果收集器信息
获取阶段(Fetch Phase)
fetch:文档获取详情load_source:源数据加载时间
聚合阶段(Aggregation Phase)
- 聚合操作执行详情
🎯两者区别
| 特性 | Explain | Profile |
|---|---|---|
| 目的 | 解释评分机制 | 分析性能瓶颈 |
| 输出 | 评分计算详情 | 时间消耗详情 |
| 粒度 | 单个文档 | 整个查询 |
| 使用场景 | 相关性调试 | 性能优化 |
💡实际应用示例
Explain 示例结果:
"_explanation": { "value": 0.0, "description": "sum of:", "details": [ { "value": 0.0, "description": "match on required clause, product of:", "details": [ { "value": 0.0, "description": "# clause", "details": [] }, { "value": 1.0, "description": "prize_type:[8 TO 8]", "details": [] } ] }, { "value": 0.0, "description": "match on required clause, product of:", "details": [ { "value": 0.0, "description": "# clause", "details": [] }, { "value": 1.0, "description": "DocValuesFieldExistsQuery [field=reward_time]", "details": [] } ] }, { "value": 0.0, "description": "match on required clause, product of:", "details": [ { "value": 0.0, "description": "# clause", "details": [] }, { "value": 1.0, "description": "es_delete_flag:F", "details": [] } ] } ] }🔍整体含义
value: 0.0:这个文档的最终相关性评分是0分description: "sum of:":总评分是由多个子评分相加得到的
📋三个必须子句分析
您的查询包含三个必须匹配的条件,每个条件都产生了0分:
1.第一个条件:prize_type 匹配
{ "value": 0.0, "description": "match on required clause, product of:", "details": [ {"value": 0.0, "description": "# clause", "details": []}, {"value": 1.0, "description": "prize_type:[8 TO 8]", "details": []} ] }- ✅
prize_type:[8 TO 8]:值为1.0,表示prize_type=8匹配成功 - ❓
# clause:值为0.0,这是Elasticsearch内部计算的一个因子
2.第二个条件:reward_time 字段存在性检查
{ "value": 0.0, "description": "match on required clause, product of:", "details": [ {"value": 0.0, "description": "# clause", "details": []}, {"value": 1.0, "description": "DocValuesFieldExistsQuery [field=reward_time]", "details": []} ] }- ✅
DocValuesFieldExistsQuery [field=reward_time]:值为1.0,表示reward_time字段存在 - ❓
# clause:值为0.0
3.第三个条件:es_delete_flag 匹配
{ "value": 0.0, "description": "match on required clause, product of:", "details": [ {"value": 0.0, "description": "# clause", "details": []}, {"value": 1.0, "description": "es_delete_flag:F", "details": []} ] }- ✅
es_delete_flag:F:值为1.0,表示es_delete_flag="F"匹配成功 - ❓
# clause:值为0.0
🎯关键结论
所有三个条件都匹配成功:
prize_type=8✅reward_time字段存在 ✅es_delete_flag="F"✅
但最终评分是0:
- 这是因为您使用的是
filter上下文(不是query上下文) - 在过滤上下文中,Elasticsearch不计算相关性评分,所有匹配文档的评分都是0
- 这是正常且预期的行为!
- 这是因为您使用的是
# clause值为0的解释:- 这是Elasticsearch内部用于计算的一个因子
- 在filter上下文中,这个值被设置为0,因为不需要计算相关性
💡为什么这样设计?
- 性能优化:filter上下文跳过评分计算,性能更好
- 缓存友好:filter结果可以被缓存,提高查询速度
- 布尔逻辑:只关心"是否匹配",不关心"匹配程度"
✅您的查询是正常的!
您的查询完全正确,所有条件都匹配成功。评分为0是filter上下文的正常行为,表示:
- ✅ 文档匹配所有过滤条件
- ✅ 应该被包含在结果集中
- ✅ 只是没有计算相关性评分而已
不需要担心这个0分,这是Elasticsearch filter查询的标准行为!
Profile 示例结果:
"profile": { "shards": [ { "id": "[REHyAdbwSWS8DMd8dOCkGQ][marketing_test_drcn-t_prize_grant_record202409][0]", "searches": [ { "query": [ { "type": "BooleanQuery", "description": "#prize_type:[8 TO 8] #ConstantScore(DocValuesFieldExistsQuery [field=reward_time]) #es_delete_flag:F", "time_in_nanos": 4064629, "breakdown": { "set_min_competitive_score_count": 0, "match_count": 0, "shallow_advance_count": 0, "set_min_competitive_score": 0, "next_doc": 3636537, "match": 0, "next_doc_count": 24754, "score_count": 0, "compute_max_score_count": 0, "compute_max_score": 0, "advance": 22021, "advance_count": 2, "score": 0, "build_scorer_count": 7, "create_weight": 31850, "shallow_advance": 0, "create_weight_count": 1, "build_scorer": 374221 }, "children": [ { "type": "IndexOrDocValuesQuery", "description": "prize_type:[8 TO 8]", "time_in_nanos": 1248668, "breakdown": { "set_min_competitive_score_count": 0, "match_count": 0, "shallow_advance_count": 0, "set_min_competitive_score": 0, "next_doc": 973861, "match": 0, "next_doc_count": 24754, "score_count": 0, "compute_max_score_count": 0, "compute_max_score": 0, "advance": 511, "advance_count": 4, "score": 0, "build_scorer_count": 9, "create_weight": 461, "shallow_advance": 0, "create_weight_count": 1, "build_scorer": 273835 } }, { "type": "ConstantScoreQuery", "description": "ConstantScore(DocValuesFieldExistsQuery [field=reward_time])", "time_in_nanos": 2578938, "breakdown": { "set_min_competitive_score_count": 0, "match_count": 0, "shallow_advance_count": 0, "set_min_competitive_score": 0, "next_doc": 0, "match": 0, "next_doc_count": 0, "score_count": 0, "compute_max_score_count": 0, "compute_max_score": 0, "advance": 2561666, "advance_count": 24756, "score": 0, "build_scorer_count": 9, "create_weight": 4428, "shallow_advance": 0, "create_weight_count": 1, "build_scorer": 12844 }, "children": [ { "type": "DocValuesFieldExistsQuery", "description": "DocValuesFieldExistsQuery [field=reward_time]", "time_in_nanos": 923343, "breakdown": { "set_min_competitive_score_count": 0, "match_count": 0, "shallow_advance_count": 0, "set_min_competitive_score": 0, "next_doc": 0, "match": 0, "next_doc_count": 0, "score_count": 0, "compute_max_score_count": 0, "compute_max_score": 0, "advance": 914637, "advance_count": 24756, "score": 0, "build_scorer_count": 9, "create_weight": 300, "shallow_advance": 0, "create_weight_count": 1, "build_scorer": 8406 } } ] }, { "type": "TermQuery", "description": "es_delete_flag:F", "time_in_nanos": 1060002, "breakdown": { "set_min_competitive_score_count": 0, "match_count": 0, "shallow_advance_count": 0, "set_min_competitive_score": 0, "next_doc": 0, "match": 0, "next_doc_count": 0, "score_count": 0, "compute_max_score_count": 0, "compute_max_score": 0, "advance": 1020038, "advance_count": 24757, "score": 0, "build_scorer_count": 9, "create_weight": 9127, "shallow_advance": 0, "create_weight_count": 1, "build_scorer": 30837 } } ] } ], "rewrite_time": 10349, "collector": [ { "name": "SimpleFieldCollector", "reason": "search_top_hits", "time_in_nanos": 3358378 } ] } ], "aggregations": [] }, { "id": "[SQYmE1nZRpiq2RL4t8yaKQ][marketing_test_drcn-t_prize_grant_record202409][1]", ... }, { "id": "[SQYmE1nZRpiq2RL4t8yaKQ][marketing_test_drcn-t_prize_grant_record202409][2]", ... } ] }这个 Profile 结果显示了您的 Elasticsearch 查询在3个分片上的详细性能分析。让我为您详细解读:
🔍整体查询结构
您的查询包含三个必须条件:
prize_type:[8 TO 8]- prize_type等于8ConstantScore(DocValuesFieldExistsQuery [field=reward_time])- reward_time字段存在es_delete_flag:F- es_delete_flag等于"F"
⏱️性能关键指标
分片0:
- 总查询时间:4,064,629 纳秒 ≈4.06毫秒
- 处理文档数:24,754 个文档
- 主要耗时:
next_doc操作(3.64毫秒)
分片1:
- 总查询时间:3,870,708 纳秒 ≈3.87毫秒
- 处理文档数:24,267 个文档
- 主要耗时:
next_doc操作(3.46毫秒)
分片2:
- 总查询时间:3,855,221 纳秒 ≈3.86毫秒
- 处理文档数:24,513 个文档
- 主要耗时:
next_doc操作(3.47毫秒)
🎯性能瓶颈分析
1.主要耗时操作:
next_doc:占查询时间的85-90%,这是遍历文档的主要操作advance:在reward_time和es_delete_flag查询中消耗较多时间
2.各子查询性能:
prize_type:[8 TO 8]:性能最好,主要耗时在next_docreward_time字段存在检查:性能较差,advance操作耗时严重es_delete_flag:F:性能中等,advance操作耗时较多
💡问题识别
🔴主要性能问题:
DocValuesFieldExistsQuery性能瓶颈:- 检查
reward_time字段是否存在消耗了大量时间 - 每个分片需要 advance 操作约2.4万次
- 检查
es_delete_flag查询优化空间:- Term查询的advance操作也有优化空间
🟢良好表现:
prize_type范围查询性能良好- 三个分片性能相对均衡(3.8-4.1毫秒)
- 查询重写时间很短(10-25微秒)
🚀最佳实践
Explain 使用时机:
- 当搜索结果不符合预期时
- 需要理解评分模型时
- 调试 boosting 和权重设置
Profile 使用时机:
- 查询响应时间过长时
- 需要优化复杂聚合时
- 识别索引或映射问题
生产环境注意:
- 两者都会增加查询开销,避免在生产环境频繁使用
- 建议在开发或测试环境进行调试
问题!!!
public static SearchSourceBuilder page(SearchSourceBuilder builder, PageDto page) { builder.trackTotalHits(true); //builder.trackTotalHits(false); // es 分页从 0 开始 builder.from((page.getPageNum() - 1) * page.getPageSize()) .size(page.getPageSize()); return builder; } SearchSourceBuilder sourceBuilder = new SearchSourceBuilder() .query(boolQuery) // 构建排序 .sort(SortBuilders.fieldSort(Constants.REWARD_TIME).order(SortOrder.DESC)) .sort(SortBuilders.fieldSort(Constants.GRANT_ID).order(SortOrder.DESC)); PageHelper.page(sourceBuilder, req.getPage()); // 构建请求 searchRequest.source(sourceBuilder); log.info("hit es [prize-grant-record] mapper, param:[{}]", searchRequest); // 执行查询 SearchResponse response = clientFactory.getInstance().search(searchRequest, RequestOptions.DEFAULT); return ResponseConverter.convert(response.getHits(), cls);如果builder.trackTotalHits(true),映射查询语句:
{ "from": 45, "size": 15, "query": { "bool": { "filter": [{ "range": { "reward_time": { "from": "2026-02-27 19:24:30", "to": "2026-03-02 19:24:30", "include_lower": true, "include_upper": true, "boost": 1.0 } } }, { "term": { "es_delete_flag": { "value": "false", "boost": 1.0 } } }], "adjust_pure_negative": true, "boost": 1.0 } }, "sort": [{ "reward_time": { "order": "desc" } }, { "grant_id": { "order": "desc" } }], "track_total_hits": 2147483647 }会默认把符合查询条件的总记录数查出来!
🔍主要性能问题分析
1.track_total_hits: 2147483647 问题
严重程度:⭐⭐⭐⭐⭐
"track_total_hits": 2147483647问题分析:
- 这个设置强制ES计算精确的命中总数,即使有数百万条记录
- ES默认只返回前10,000个匹配文档的计数,设置此值会显著增加查询开销
- 对于大数据量的索引,计算精确总数非常消耗资源
建议解决方案:
// 移除或限制track_total_hits "track_total_hits": false // 或者设置一个合理的上限 "track_total_hits": 10000======================
如果builder.trackTotalHits(false),映射查询语句:
{ "from": 45, "size": 15, "query": { "bool": { "filter": [{ "range": { "reward_time": { "from": "2026-02-27 19:24:30", "to": "2026-03-02 19:24:30", "include_lower": true, "include_upper": true, "boost": 1.0 } } }, { "term": { "es_delete_flag": { "value": "false", "boost": 1.0 } } }], "adjust_pure_negative": true, "boost": 1.0 } }, "sort": [{ "reward_time": { "order": "desc" } }, { "grant_id": { "order": "desc" } }], "track_total_hits": -1 }不会查出总记录数!可以使用_count查出总数,结合_search查询当前页数据,一起返回给前端,进行分页计算总页数,count和search可以使用两个线程异步一起查询。