千家信息网

如何解决ES深度分页问题

发表于:2024-11-12 作者:千家信息网编辑
千家信息网最后更新 2024年11月12日,这篇文章主要介绍"如何解决ES深度分页问题",在日常操作中,相信很多人在如何解决ES深度分页问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"如何解决ES深度分页问题"
千家信息网最后更新 2024年11月12日如何解决ES深度分页问题

这篇文章主要介绍"如何解决ES深度分页问题",在日常操作中,相信很多人在如何解决ES深度分页问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"如何解决ES深度分页问题"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

ES深度分页问题:

ES 默认采用的分页方式是 from+ size 的形式,类似于MySQL的分页offset+limit。当请求数据量比较大时,Elasticsearch会对分页做出限制,因为此时性能消耗会很大。例如查询1000条数据,假设我们有5个分片,那么每个shard都需要返回1000条数据给 coordinating node,而 coordinating node 需要接收 5*1000 条数据,进行排序后返回1000条数据给客户端。即使每条数据只有 _doc _id 和 _score,这数据量也很大了,如果请请求量很大的情况下,很容易造成ES的OOM。ES中有个设置index.max_result_window ,默认是10000条数据,如果分页的数据超过第1万条,就拒绝返回结果了。如果集群配置比较好,查询请求量不是特别大,可以适当的放大这个参数。

解决方案:

1:使用scroll遍历

scroll 分为初始化和遍历两步,初始化时将所有符合搜索条件的搜索结果缓存起来,可以想象成快照,在遍历时,从这个快照里取数据,也就是说,在初始化后对索引插入、删除、更新数据都不会影响遍历结果。因此,scroll 并不适合用来做实时搜索,而更适用于后台批处理任务等

API说明:

1)初始化

POST /book/_search?scroll=1m&size=2{"query": { "match_all": {}}}
  1. 遍历

GET /_search/scroll{"scroll": "1m","scroll_id" : "步骤1中查询出来的值"}

使用java RestHighLevelClient代码参考如下:

@Autowiredprivate RestHighLevelClient restHighLevelClient;public Result  scrollSearch(...查询参数){     BoolQueryBuilder queryBuilder.te = QueryBuilders.boolQuery();     //添加自己的搜索条件....     queryBuilder.must(QueryBuilders.termQuery("type", "商品所属分类);     queryBuilder.must(QueryBuilders.matchQuery("name", "商品名称");     //搜索     SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.searchSource();     searchSourceBuilder.query(queryBuilder);     //排序     searchSourceBuilder.sort(SortBuilders.fieldSort("order").order(SortOrder.DESC));     //搜索结果     SearchResponse searchResponse = null;     //根据实际情况,判断是多次调用还是一次while遍历查询全部      if (StringUtils.isBlank("scrollId")) {            //首屏            searchSourceBuilder.size("每次查询的条数");            SearchRequest searchRequest = new SearchRequest();            searchRequest.indices("索引名").source(searchSourceBuilder);            searchRequest.scroll(new Scroll(TimeValue.timeValueMinutes(scrollKeepAliveTime)));            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);     } else {            //后续根据上次的id滚动            SearchScrollRequest searchScrollRequest = new SearchScrollRequest("scrollId");            searchScrollRequest.scroll(new Scroll(TimeValue.timeValueMinutes(scrollKeepAliveTime)));            searchResponse = restHighLevelClient.scroll(searchScrollRequest, RequestOptions.DEFAULT);     }             SearchHit[] hits = searchResponse.getHits().getHits();     //根据业务需求,处理搜索结果     GoodsDTO result= handleSearchData(hits);     //scrollId,往下滚动需要使用     String scrollId = searchResponse.getScrollId();     return Result.succcess(result);}

2:使用search after

满足实时获取下一页的文档信息,search_after 分页的方式是根据上一页的最后一条数据来确定下一页的位置,同时在分页请求的过程中,如果有索引数据的增删改,这些变更也会实时的反映到游标上,这种方式是在es-5.X之后才提供的。为了找到每一页最后一条数据,每个文档的排序字段必须有一个全局唯一值使用 _id 就可以了。

API说明:

GET /book/_search{    "query": {"match_all": {}},    "size": 2,    "sort": [{"_id": "desc"}]}GET /book/_search{    "query": {"match_all": {}},    "size": 2,    "search_after": [3],    "sort": [{"_id": "desc"}]}

下一页的数据依赖上一页的最后一条的信息 所以不能跳页

使用java RestHighLevelClient代码参考如下:

@Autowiredprivate RestHighLevelClient restHighLevelClient;public Result  searchAfter(...查询参数){        SearchRequest searchRequest = new SearchRequest(index);        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();        searchSourceBuilder.query(...搜索条件);        searchSourceBuilder.size(1000);        searchSourceBuilder.sort("_id", SortOrder.ASC);        searchSourceBuilder.searchAfter("上一页最后一条数据的id");        searchRequest.source(searchSourceBuilder);        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);        SearchHit[] hits = searchResponse.getHits().getHits();         //根据业务需求,处理搜索结果         GoodsDTO result= handleSearchData(hits);         return Result.succcess(result);}

到此,关于"如何解决ES深度分页问题"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

0