前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >业务自增id彻底解决es深翻页的问题

业务自增id彻底解决es深翻页的问题

作者头像
逍遥壮士
发布2020-09-18 11:31:45
1.5K0
发布2020-09-18 11:31:45
举报
文章被收录于专栏:技术趋势技术趋势

背景

由于原来mysql库里面的数据量从2万增加到40万,并且mysql库缩容导致,每小时其他项目级小伙伴来调xinyun库的这张表导致cpu每次开销都在20%以上,并且该库数据可能还会继续增加,每次拉数据会延长到半小时左右,非常耗能,所以将原有的mysql表同步到es中...,但是发现es翻页到一万条数据后就会出现以下问题。

通过查询发现该问题在es使用中普遍存在,有三种方案:

一、 max_result_window 的值调至 50000。

代码语言:javascript
复制
[root@dnsserver ~]# curl -XPUT "127.0.0.1:9200/custm/_settings" -d 
'{ 
    "index" : { 
        "max_result_window" : 50000 
    }
}'

二、通过scroll分页通过游标来获取;

三、通过scroll after 来通过上下页;

通过业务的分析和尝试,发现以上的三种方案都行不通....

方案一,这个可能会影响整个集群,不能随便改;

方案二和三,因为原有的接口传过来一个页码,原接口现在暂时不支持修改,所以如果要改可能要让原来下游接换接口,并且无法返回游标过来,这个比较头大。

尝试过的方案:

将游标放到缓存中-------->存在一定风险,因为页数是一页一页翻页,如果哪天来一个突然间100页的,不支指定页码,并且还有可能存在死循环调用风险。

通过传入的页面,循环获取游标不断提交,这个时间太长了代码和时间如下:

通过指定循环到指定页码获取,发现前十页还好,后面就...

6秒多.....有点恐怖。

然后不断的寻找问题的解决方案中,不断尝试...。在同事的分享下,彻底解决了该问题,真的非常给力;

解决方案:

通过原数据库自增Id将通过条件方式进行区间条件查询,每次分页请求的时候,通过页码*条数获取指定范围的条数就解决了该问题。

代码实现

代码语言:javascript
复制
@Override
public DataRO queryByCondition(PopFlowConfigQueryAo queryAo) {
    LOGGER.info("查询参数:{}", JSONObject.toJSONString(queryAo));
    SearchRequestBuilder searchRequestBuilder = buildSearchRequestBuilder();
    BoolQueryBuilder boolQueryBuilder = boolQuery();
    if(null!=queryAo && queryAo.getPageAO()!=null && queryAo.getPageAO().getPageIndex() != 0 && queryAo.getPageAO().getPageSize()!= 0){
        int page = (queryAo.getPageAO().getPageIndex()-1);
         
     //   searchRequestBuilder.setSize(queryAo.getPageAO().getPageSize());
        RangeQueryBuilder rangeCreate = QueryBuilders.rangeQuery("popFlowConfigId");
        int index = page * queryAo.getPageAO().getPageSize();
        rangeCreate.gte(index);
        int size = ((1+page)* queryAo.getPageAO().getPageSize())-1;
        rangeCreate.lt(size);
        boolQueryBuilder.must(rangeCreate);
    }else{
        searchRequestBuilder.setSize(10000);
    }
    searchRequestBuilder.setQuery(boolQueryBuilder);
    searchRequestBuilder.addSort("popFlowConfigId", SortOrder.ASC);
    LOGGER.info("pop查询{}", searchRequestBuilder.toString());
    SearchResponse searchResponse = searchRequestBuilder.get();
    DataRO> response = new DataRO<>();
    List resultList = new ArrayList<>();
    SearchHits hits=searchResponse.getHits();
    int count = (int) searchResponse.getHits().totalHits;
    LOGGER.info("查询总条数{}",count);
    List list = BeanUtil.transformListBean(hits, PopFlowConfigRo.class);
    if (list != null && list.size() > 0) {
        resultList.addAll(list);
    }
    response.setData(resultList);
    return response;
}

通过排序popFlowConfigId为正序;

再通过原数据库主键:popFlowConfigId 进行区间的条件查询,比如

传入页码为1的时候通过代码:

默认减1当成0,由于es也是通过区间rangeQuery

代码语言:javascript
复制
popFlowConfigId>= 0 * size = 0;
popFlowConfigId<((1+page) * 1000)-1;

通过这个算出:

代码语言:javascript
复制
page = 1
form -> 0 ,size -> 999
range  0 ~ 999
page = 2
form -> 0 ,size -> 999
range  1000 ~ 1999
....

得出 from=0 size=999 这里就类似数据库的 0~999区间,这样的话也就是说,每只查出这个popFlowConfigId在这个区间中的数据,一页一页的查,并且解决了由于scroll 或scroll after无法指定页码查询问题或需要通过游标,而且性能也非常高。

优化后

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-07-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 技术趋势 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档