其他分享
首页 > 其他分享> > ElasticSearch深度分页详解

ElasticSearch深度分页详解

作者:互联网

1 前言

ElasticSearch是一个实时的分布式搜索与分析引擎,常用于大量非结构化数据的存储和快速检索场景,具有很强的扩展性。纵使其有诸多优点,在搜索领域远超关系型数据库,但依然存在与关系型数据库同样的深度分页问题,本文就此问题做一个实践性分析探讨

2 from + size分页方式

from + size分页方式是ES最基本的分页方式,类似于关系型数据库中的limit方式。from参数表示:分页起始位置;size参数表示:每页获取数据条数。例如:

GET /wms_order_sku/_search
{
  "query": {
    "match_all": {}
  },
  "from": 10,
  "size": 20
}

 

该条DSL语句表示从搜索结果中第10条数据位置开始,取之后的20条数据作为结果返回。这种分页方式在ES集群内部是如何执行的呢?

在ES中,搜索一般包括2个阶段,Query阶段和Fetch阶段,Query阶段主要确定要获取哪些doc,也就是返回所要获取doc的id集合,Fetch阶段主要通过id获取具体的doc。

2.1 Query阶段

 

如上图所示,Query阶段大致分为3步:

2.2 Fetch阶段

 

如上图所示,当Query阶段结束后立马进入Fetch阶段,Fetch阶段也分为3步:

2.3 ES示例

依据上述我们对from + size分页方式两阶段的分析会发现,假如起始位置from或者页条数size特别大时,对于数据查询和coordinating node结果合并都是巨大的性能损耗。

例如:索引 wms_order_sku 有1亿数据,分10个shard存储,当一个请求的from = 1000000, size = 10。在Query阶段,每个shard就需要返回1000010条数据的_id和_score信息,而coordinating node就需要接收10 * 1000010条数据,拿到这些数据后需要进行全局排序取到前1000010条数据的_id集合保存到coordinating node的优先级队列中,后续在Fetch阶段再去获取那10条数据的详情返回给客户端。

分析:这个例子的执行过程中,在Query阶段会在每个shard上均有巨大的查询量,返回给coordinating node时需要执行大量数据的排序操作,并且保存到优先级队列的数据量也很大,占用大量节点机器内存资源。

2.4 实现示例

 

private SearchHits getSearchHits(BoolQueryBuilder queryParam, int from, int size, String orderField) {
        SearchRequestBuilder searchRequestBuilder = this.prepareSearch();
        searchRequestBuilder.setQuery(queryParam).setFrom(from).setSize(size).setExplain(false);
        if (StringUtils.isNotBlank(orderField)) {
            searchRequestBuilder.addSort(orderField, SortOrder.DESC);
        }
        log.info("getSearchHits searchBuilder:{}", searchRequestBuilder.toString());
        SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
        log.info("getSearchHits searchResponse:{}", searchResponse.toString());
        return searchResponse.getHits();
    }

标签:ElasticSearch,搜索,数据,优点,分析,DSL,Query
来源: