Elasticsearch海量数据查询优化:深度分页与聚合查询提速方案
在日常后端开发中只要涉及日志检索、订单大数据列表、业务统计报表基本都会用到 Elasticsearch。相比于MySQLES在全文检索、海量数据筛选上优势非常大。但很多朋友上线后会遇到一个很头疼的问题首页浅分页秒开一旦翻到几十页之后接口直接超时简单查询很快带聚合统计的报表直接卡死。我前段时间负责公司日志平台优化原始数据量达到千万级别项目初期直接用默认fromsize分页、普通agg聚合深度分页直接报错、聚合查询耗时飙升到数秒。踩了很多坑之后终于整理出一套稳定落地的ES提速方案。今天就结合真实线上问题分享ES海量数据下深度分页、聚合查询的完整优化思路附带错误代码和优化后可直接上线的Java代码帮大家彻底解决ES慢查询问题。一、先说说为什么ES深度分页会超时很多新手习惯沿用MySQL思维直接用 from size 实现分页在数据量小的时候完全没问题。但在海量数据下这种写法堪称性能杀手。ES是分布式架构深度分页时需要在所有分片上查询前N条数据、做全局排序、合并结果再截断返回。页码越深需要排序和合并的数据量越大内存开销极高。这也是为什么ES官方会限制默认最大分页深度深度过大会直接抛出Result window is too large异常不仅慢还极易引发OOM风险。二、线上原始低效代码典型踩坑案例下面是我之前项目的原始写法也是网上很多教程的通用错误示范浅分页没问题深度分页直接崩// 【错误写法fromsize 不支持深度分页】 public ListLogDTO getLogPage(int pageNum, int pageSize){ NativeSearchQueryBuilder queryBuilder new NativeSearchQueryBuilder(); // 普通条件查询 queryBuilder.withQuery(QueryBuilders.matchQuery(type,operation)); // 传统分页 int from (pageNum - 1) * pageSize; queryBuilder.withPageable(PageRequest.of(from, pageSize)); SearchHitsLogDTO hits elasticsearchRestTemplate.search( queryBuilder.build(), LogDTO.class); return hits.stream().map(hit - hit.getContent()).collect(Collectors.toList()); }测试发现pageNum超过50页之后接口响应从几十毫秒直接涨到2秒以上页码越大越慢完全无法满足后台列表翻页需求。三、深度分页最优方案Scroll SearchAfter 实战优化针对海量数据分页生产环境主流且稳定的方案就是SearchAfter。它不依赖偏移量通过上一页最后一条数据的排序值向后遍历没有深度损耗越翻页速度越稳定。适合后台大数据列表、批量数据导出、日志查询场景我给大家贴出精简可复用代码// 优化后SearchAfter 深度分页 public ListLogDTO searchAfterPage(Long lastTime, int pageSize){ NativeSearchQueryBuilder queryBuilder new NativeSearchQueryBuilder(); queryBuilder.withQuery(QueryBuilders.matchQuery(type,operation)); // 必须设置排序字段唯一有序字段建议时间ID SortBuilders.FieldSortBuilder sort SortBuilders.fieldSort(createTime).order(SortOrder.DESC); queryBuilder.withSort(sort); // 传递上一页最后一条排序值 if(lastTime ! null){ queryBuilder.withSearchAfter(Collections.singletonList(lastTime)); } queryBuilder.withPageable(PageRequest.of(0, pageSize)); SearchHitsLogDTO hits elasticsearchRestTemplate.search( queryBuilder.build(), LogDTO.class); return hits.stream().map(hit - hit.getContent()).collect(Collectors.toList()); }优化后无论翻到多少页响应速度始终稳定在100ms以内彻底解决深度分页超时问题。这里提醒一句SearchAfter不适合跳页查询只适合下拉滚动翻页、顺序遍历这也是大数据列表的主流交互方式。四、聚合查询卡顿解决方案除了分页问题聚合统计也是ES的性能重灾区。很多人直接写多层聚合、超大范围时间聚合导致报表查询卡死。我优化线上报表的核心思路缩小查询范围、拆分聚合层级、开启字段预聚合、禁止深度排序聚合。简单实用的聚合优化代码// 分组聚合查询优化 public MapString,Long logAggSearch(){ NativeSearchQueryBuilder queryBuilder new NativeSearchQueryBuilder(); // 时间范围过滤缩小聚合扫描区间核心优化点 QueryBuilder timeQuery QueryBuilders.rangeQuery(createTime).gte(now-7d); queryBuilder.withQuery(timeQuery); // 单层简单聚合避免多层嵌套 TermsAggregationBuilder agg AggregationBuilders.terms(group_by_user) .field(userId.keyword) .size(100); queryBuilder.addAggregation(agg); // 关闭结果集只需要聚合不需要列表 queryBuilder.withPageable(PageRequest.of(0,0)); SearchHitsLogDTO hits elasticsearchRestTemplate.search( queryBuilder.build(), LogDTO.class); // 解析聚合数据... return new HashMap(); }五、额外几条生产级优化小技巧1、聚合字段务必设置为 keyword 类型文本类型聚合会极大拖慢速度 2、超大报表统计不要实时查ES建议定时同步到MySQL做统计展示 3、高频查询字段建立索引不需要检索的字段关闭存储 4、避免模糊匹配 *xxx 前置通配符会导致索引失效。总结ES海量数据慢查询90%都是用法问题而非组件性能问题。传统fromsize只适合前台浅分页展示深度分页一定要用SearchAfter报表聚合一定要缩小范围、精简层级。这套优化方案我已经在线上千万级数据量验证过分页、聚合速度提升非常明显完全可以直接复用在自己的项目中轻松解决ES接口超时、报表卡顿难题。nht.4-p.cNexk.4-p.cN1js.4-p.cN8kB.4-p.cNog0.4-p.cNt6m.4-p.cNt37.4-p.cNzth.4-p.cN6DD.4-p.cNnx0.4-p.cNCq7.4-p.cN0tC.4-p.cNlm7.4-p.cN6iu.4-p.cNrik.4-p.cN92p.4-p.cN0r1.4-p.cNhv8.4-p.cN7Ay.4-p.cNflh.4-p.cNqDC.4-p.cN74f.4-p.cNvrs.4-p.cN9jy.4-p.cN5gn.4-p.cNtnn.4-p.cNskr.4-p.cNu3e.4-p.cN513.4-p.cN2lx.4-p.cNkp9.4-p.cN9l3.4-p.cNut4.4-p.cNkhn.4-p.cNw9i.4-p.cNAkx.4-p.cNj3q.4-p.cNpfw.4-p.cN3Be.4-p.cNDff.4-p.cN4Au.4-p.cNAwe.4-p.cNfoe.4-p.cN7f2.4-p.cN4zo.4-p.cNy2o.4-p.cNuyp.4-p.cN1uh.4-p.cNCy0.4-p.cNkBk.4-p.cNggk.4-p.cNmkf.4-p.cN407.4-p.cNmr2.4-p.cN6BD.4-p.cNg0q.4-p.cNfhz.4-p.cNfjp.4-p.cN1jD.4-p.cNBzv.4-p.cNvy1.4-p.cN4g7.4-p.cNBBB.4-p.cNCou.4-p.cN5gz.4-p.cNfjm.4-p.cNgBx.4-p.cNmyv.4-p.cNmye.4-p.cN118.4-p.cN2e1.4-p.cNlpe.4-p.cN9rx.4-p.cN1lC.4-p.cN7qA.4-p.cN7ko.4-p.cNDpg.4-p.cNy84.4-p.cNCBe.4-p.cNCyz.4-p.cNBwp.4-p.cNeCh.4-p.cNB9B.4-p.cNllD.4-p.cN2zy.4-p.cN7Dw.4-p.cNr5q.4-p.cNp9g.4-p.cNCBw.4-p.cNsv8.4-p.cNp6A.4-p.cNe00.4-p.cN045.4-p.cNwsi.4-p.cNuuD.4-p.cNyru.4-p.cN7mm.4-p.cNxvl.4-p.cNizp.4-p.cNk2v.4-p.cNimt.4-p.cN7vj.4-p.cNA7B.4-p.cNf62.4-p.cNuq2.4-p.cNqiy.4-p.cN3ww.4-p.cNppk.4-p.cN05e.4-p.cNi86.4-p.cNu9p.4-p.cN3Cr.4-p.cNhuC.4-p.cN9hy.4-p.cN0ht.4-p.cNxD0.4-p.cN5iC.4-p.cNuph.4-p.cNoqx.4-p.cN5v6.4-p.cNjxz.4-p.cN17u.4-p.cNxC4.4-p.cNm0s.4-p.cNqf7.4-p.cN6mu.4-p.cN6lt.4-p.cNsD7.4-p.cNCw3.4-p.cN7ge.4-p.cNoqv.4-p.cNsql.4-p.cNgun.4-p.cNvhy.4-p.cNo9s.4-p.cNs0s.4-p.cN9hD.4-p.cNwot.4-p.cNiAu.4-p.cNjee.4-p.cNgoe.4-p.cN2s7.4-p.cN8C5.4-p.cNv21.4-p.cNekh.4-p.cN9n1.4-p.cNs0v.4-p.cNug1.4-p.cNBw6.4-p.cNq68.4-p.cN8wk.4-p.cN4us.4-p.cN2i2.4-p.cNqlg.4-p.cNwqA.4-p.cNgBm.4-p.cNi9e.4-p.cN9w8.4-p.cNDv0.4-p.cNlp3.4-p.cNig6.4-p.cNDeu.4-p.cNw3h.4-p.cNyt5.4-p.cN2Dx.4-p.cNCwq.4-p.cN3ng.4-p.cN83s.4-p.cN4yh.4-p.cN5hC.4-p.cNwDr.4-p.cNftk.4-p.cNnsf.4-p.cN1w8.4-p.cNyty.4-p.cNxC1.4-p.cNuzm.4-p.cNxwn.4-p.cNxl2.4-p.cNlyr.4-p.cND4v.4-p.cN9he.4-p.cNBpC.4-p.cNvko.4-p.cNoDo.4-p.cNxek.4-p.cN00g.4-p.cNpwm.4-p.cNpnv.4-p.cN99k.4-p.cN96D.4-p.cN9su.4-p.cNiCC.4-p.cN49C.4-p.cN7eq.4-p.cNsix.4-p.cNevl.4-p.cNiiB.4-p.cNh0h.4-p.cNxq7.4-p.cN43A.4-p.cNzvz.4-p.cN6ff.4-p.cNw7z.4-p.cN2zv.4-p.cNk76.4-p.cNy9l.4-p.cNu00.4-p.cN84r.4-p.cNC11.4-p.cN5hk.4-p.cN1sk.4-p.cNwts.4-p.cNxAh.4-p.cN3fl.4-p.cNm1j.4-p.cN0qB.4-p.cNehe.4-p.cNA9n.4-p.cN0f7.4-p.cN6zz.4-p.cN5if.4-p.cN7yh.4-p.cNh0x.4-p.cNghs.4-p.cNuCw.4-p.cN7ms.4-p.cNvgx.4-p.cNgqg.4-p.cNrin.4-p.cNlfp.4-p.cNDm7.4-p.cN8t0.4-p.cNilD.4-p.cN92g.4-p.cN8p9.4-p.cNgn0.4-p.cNgpD.4-p.cNs41.4-p.cNeos.4-p.cNk7j.4-p.cN1qs.4-p.cN36m.4-p.cNzuh.4-p.cNqAe.4-p.cNwCw.4-p.cNjrB.4-p.cNqvv.4-p.cNw23.4-p.cNj1u.4-p.cN1sf.4-p.cNzx2.4-p.cN6en.4-p.cNpAp.4-p.cN8uB.4-p.cNCnB.4-p.cNCu7.4-p.cNBt3.4-p.cNC5n.4-p.cNmeh.4-p.cN5k3.4-p.cNwno.4-p.cNpnf.4-p.cNqpe.4-p.cNe6i.4-p.cN9BD.4-p.cN0kl.4-p.cNs0e.4-p.cNeB9.4-p.cN4C8.4-p.cNiDl.4-p.cNzq6.4-p.cNsvl.4-p.cN8jD.4-p.cNlm3.4-p.cNn88.4-p.cNgnt.4-p.cNis2.4-p.cNp1q.4-p.cN470.4-p.cNvDe.4-p.cNC5k.4-p.cNm21.4-p.cNhok.4-p.cNBgo.4-p.cN1iq.4-p.cNgjz.4-p.cNiv0.4-p.cNrrh.4-p.cN7h8.4-p.cNui1.4-p.cNuD7.4-p.cNw6w.4-p.cN91s.4-p.cNmwD.4-p.cNfDC.4-p.cN4Aw.4-p.cN5er.4-p.cN9ut.4-p.cNkxf.4-p.cN4Cz.4-p.cN6Bs.4-p.cN9uu.4-p.cNDnA.4-p.cNACu.4-p.cN1fw.4-p.cNBi1.4-p.cNu9z.4-p.cNtuC.4-p.cNBpz.4-p.cNh0q.4-p.cNvi5.4-p.cNqxC.4-p.cNC3o.4-p.cNk41.4-p.cN2sB.4-p.cN1l5.4-p.cNm6t.4-p.cNwvv.4-p.cNs55.4-p.cNmiw.4-p.cNlk8.4-p.cN4n5.4-p.cNhfy.4-p.cNDso.4-p.cNqzA.4-p.cN0BB.4-p.cN0n2.4-p.cNxt3.4-p.cN3nj.4-p.cN3AD.4-p.cNg45.4-p.cNhD4.4-p.cN7gB.4-p.cNj1p.4-p.cNuru.4-p.cNyvi.4-p.cNmB0.4-p.cNtg7.4-p.cNnzx.4-p.cN2e4.4-p.cNf9x.4-p.cNtr1.4-p.cNn47.4-p.cNg86.4-p.cNzo2.4-p.cN0iz.4-p.cN4eA.4-p.cN5q5.4-p.cNA3p.4-p.cNo00.4-p.cNn28.4-p.cNw9u.4-p.cNfAA.4-p.cNsz1.4-p.cNjz5.4-p.cN6ht.4-p.cNh39.4-p.cNzgr.4-p.cN