深度分页存在的问题

https://segmentfault.com/a/1190000019004316?utm_source=tag-newest

在实际应用中,分页是必不可少的,例如,前端页面展示数据给用户往往都是分页进行展示的。

1、ES分页搜索
Elasticsearch分页搜索采用的是from+size。from表示查询结果的起始下标,size表示从起始下标开始返回文档的个数。
示例:

什么是深分页(deep paging)?简单来说,就是搜索的特别深,比如总共有60000条数据,三个primary shard,每个shard上分了20000条数据,每页是10条数据,这个时候,你要搜索到第1000页,实际上要拿到的是10001~10010。

注意这里千万不要理解成每个shard都是返回10条数据。这样理解是错误的!

下面做一下详细的分析:
请求首先可能是打到一个不包含这个index的shard的node上去,这个node就是一个协调节点coordinate node,那么这个coordinate node就会将搜索请求转发到index的三个shard所在的node上去。比如说我们之前说的情况下,要搜索60000条数据中的第1000页,实际上每个shard都要将内部的20000条数据中的第10001~10010条数据,拿出来,不是才10条,是10010条数据。3个shard的每个shard都返回10010条数据给协调节点coordinate node,coordinate node会收到总共30030条数据,然后在这些数据中进行排序,根据_score相关度分数,然后取到10001~10010这10条数据,就是我们要的第1000页的10条数据。
如下图所示:

deep paging问题就是说from + size分页太深,那么每个shard都要返回大量数据给coordinate node协调节点,会消耗大量的带宽,内存,CPU。

深度分页问题之所以存在,是和Elasticsearch搜索内部执行原理分不开的。

如果你想查询第5000-5100数据,查询官网API你很容易就知道,发送如下查询条件就可以做到:

POST auditlog_operation/operlog/_search

{

“from”:5000 //from:定义从哪里开始拿数据

“size”:100 //size:定义一共拿多少条数据

}

查询流程如下:

  1. 客户端发送请求到某个node节点。

  2. 此node将请求广播到各分片,各分片各自查询前5100条数据。

  3. 查询结果返回给node节点,node对结果进行合并整合,取出前5100条数据。

  4. 返回给客户端。

流程大概如下

相信就算是技术小白也能看出上述深度分页查询的问题,如果你要深度获取1000000到1000100页的数据,性能问题会非常明显的暴露出来:CPU、内存、IO、网络带宽等等,而且Elasticsearch本身就是个Java应用,若并发上去,Elasticsearch会快就会OOM

{
"query": {
"match_all": {}
},
"from": ,
"size":
} {
"query": {
"match_all": {}
},
"from": ,
"size":
}

我们在获取第9999条到10009条数据的时候,其实每个分片都会拿到10009条数据,然后集合在一起,总共是10009*3=30027条数据,针对30027数据再次做排序处理,最终会获取最后10条数据。

如此一来,搜索得太深,就会造成性能问题,会耗费内存和占用cpu。而且es为了性能,他不支持超过一万条数据以上的分页查询。那么如何解决深度分页带来的性能呢?其实我们应该避免深度分页操作(限制分页页数),比如最多只能提供100页的展示,从第101页开始就没了,毕竟用户也不会搜的那么深,我们平时搜索淘宝或者百度,一般也就看个10来页就顶多了。

查询请求:

POST auditlog_operation/operlog/_search

{

“from”:10000

“size”:100

}

如果你尝试发送上述from+size请求来获取10000-10100条数据,对不起会返回错误:

如果你尝试发送上述from+size请求来获取10000-10100条数据,对不起会返回错误:

{"error":{"root_cause":[{"type":"query_phase_execution_exception","reason":"Resultwindow is too large, from + size must be less than or equal to: [1000000] butwas [1000100]. See the scroll api for a more efficient way to request largedata sets. This limit can be set by changing the [index.max_result_window]index levelparameter."}],"type":"search_phase_execution_exception","reason":"allshards failed","phase":"query_fetch","grouped":true,"failed_shards":[{"shard":0,"index":"auditlog_operation","node":"iqu-KVKjTRmT3YcT9XAu_w","reason":{"type":"query_phase_execution_exception","reason":"Resultwindow is too large, from + size must be less than or equal to: [1000000] butwas [1000100]. See the scroll api for a more efficient way to request largedata sets. This limit can be set by changing the [index.max_result_window]index level parameter."}}]},"status":500}

迅速查询官网得到更明确的提示:

翻译成中文为:注意 from+size不再适用于查询数据超过index.max_result_window设置值,此默认值为10000。查看 Scroll 或 Search After来获取更高效的深层分页(滚动)。

由此可以得到两个结论:

  1. 你可以修改index.max_result_window设置值来继续使用from+size做分页查询。当然效率肯定不高。

  2. 如果要找更高效的深度分页方式,请使用Scroll 或者Search After。

Scroll API

Scroll API更适用于检索大量数据(甚至全部数据)。它先做一个初始阶段搜索然后持续批量从Elasticsearch里拉取结果直到返回结果为空。这有点像传统数据库里的cursors(游标)。

https://blog.csdn.net/lisongjia123/article/details/79041402

https://www.sohu.com/a/165387407_465944

https://segmentfault.com/a/1190000019004316?utm_source=tag-newest

除了效率上的问题,还有一个无法解决的问题是,es 目前支持最大的 skip 值是 max_result_window ,默认

为 10000 。也就是当 from + size > max_result_window 时,es 将返回错误

[root@dnsserver ~]# curl -XGET 127.0.0.1:9200/custm/_settings?pretty
{
"custm" : {
"settings" : {
"index" : {
"max_result_window" : "50000",
....
}
}
}
}
 

最开始的时候是线上客户的es数据出现问题,当分页到几百页的时候,es 无法返回数据,此时为了恢复正常使用,我们采用了紧急规避方案,就是将 max_result_window 的值调至 50000,其中custm是索引的名称,http请求提交的方式必须是put请求

[root@dnsserver ~]# curl -XPUT "127.0.0.1:9200/custm/_settings" -d
'{
"index" : {
"max_result_window" : 50000
}
}'
 

然后这种方式只能暂时解决问题,当es 的使用越来越多,数据量越来越大,深度分页的场景越来越复杂时,如何解决这种问题呢?

custm

elasticserach数据库深度分页查询的原理的更多相关文章

  1. MySQL、SQLServer2000(及SQLServer2005)和ORCALE三种数据库实现分页查询的方法

    在这里主要讲解一下MySQL.SQLServer2000(及SQLServer2005)和ORCALE三种数据库实现分页查询的方法. 可能会有人说这些网上都有,但我的主要目的是把这些知识通过我实际的应 ...

  2. oracle分页查询及原理分析(总结)

    oracle分页查询及原理分析(总结) oracle分页查询是开发总为常用的语句之一,一般情况下公司框架会提供只需套用,对于增删改查而言,查是其中最为关键也是最为难的一块,其中就有使用率最高的分页查询 ...

  3. 分页查询信息(使用jdbc连接mysql数据库实现分页查询任务)

             分页查询信息       使用jdbc连接mysql数据库实现分页查询任务 通过mysql数据库提供的分页机制,实现商品信息的分页查询功能,将查询到的信息显示到jsp页面上. 本项目 ...

  4. oracle,mysql,SqlServer三种数据库的分页查询的实例。

    MySql: MySQL数据库实现分页比较简单,提供了 LIMIT函数.一般只需要直接写到sql语句后面就行了.LIMIT子 句可以用来限制由SELECT语句返回过来的数据数量,它有一个或两个参数,如 ...

  5. MySQL数据库实现分页查询的SQL语句写法!

    一:分页需求: 客户端通过传递start(页码),limit(每页显示的条数)两个参数去分页查询数据库表中的数据,那我们知道MySql数据库提供了分页的函数limit m,n,但是该函数的用法和我们的 ...

  6. Solr中使用游标进行深度分页查询以提高效率(适用的场景下)

    通常,我们的应用系统,如果要做一次全量数据的读取,大多数时候,采用的方式会是使用分页读取的方式,然而 分页读取的方式,在大数据量的情况下,在solr里面表现并不是特别好,因为它随时可能会发生OOM的异 ...

  7. oracle,mysql,SqlServer三种数据库的分页查询

    MySql: MySQL数据库实现分页比较简单,提供了 LIMIT函数.一般只需要直接写到sql语句后面就行了.LIMIT子 句可以用来限制由SELECT语句返回过来的数据数量,它有一个或两个参数,如 ...

  8. 数据库MySQL-Oracle-DB2-SQLServer分页查询

    1. MySQL分页查询 (1)关键字: LIMIT beginIndex, maxRow (2)示例: LIMIT子句可以用来限制由SELECT语句返回过来的数据数量,它有一个或两个参数. 如果给出 ...

  9. PreparedStatement 基于mysql数据库做分页查询和统计查询

    分页查询: 统计查询:

随机推荐

  1. 自己的win7第一次使用RabbitMQ

    使用的过程中参考了https://www.cnblogs.com/longlongogo/p/6489574.html所写的内容 一.环境搭建 1.由于RabbitMQ使用Erlang语言编写,所以先 ...

  2. 多用户vps管理面板怎么安装,有没有好用的vps管理工具

    一.VPS安装VPSMate控制面板步骤 1.使用SSH连接到VPS.使用命令获取VPSMate安装包: wget   http://www.vpsmate.org/tools/install.py ...

  3. Rocket - debug - Example: Triggers

    https://mp.weixin.qq.com/s/zPNyrBOhsytkRrZTDTEvpw 介绍riscv-debug的使用实例:配置Triggers功能. 1. Trigger Trigge ...

  4. CPU efficiency测量标准:DMIPS

    DMIPS:Dhrystone Million Instructions executed Per Second ,主要用于测整数计算能力.   1.Dhrystone:是测量处理器运算能力的最常见基 ...

  5. java实现蓝桥杯密码脱落

    一 问题描述 X星球的考古学家发现了一批古代留下来的密码. 这些密码是由A.B.C.D 四种植物的种子串成的序列. 仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串). 由于年代久远 ...

  6. java实现扑克牌移动

    /* 下面代码模拟了一套扑克牌(初始排序 A~K,共 13 张)的操作过程. 操作过程是: 手里拿着这套扑克牌,从前面拿一张放在后面,再从前面拿一张放桌子上,再从前面拿一张放在后面,.... 如此循环 ...

  7. webpack从什么都不懂到入门

    前言 这篇文章是自己在整理webpack相关的东西时候突发奇想,想总结自己所学知识,也希望能够帮助想学习webpack的同学们,都是入门级别的,大佬请出门右转. 本文的webpack基于webpack ...

  8. redis基础知识详解

    一.redis基础知识 1.Redis是什么Redis是一个开源的key-value存储系统. 和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表 ...

  9. sort运用

    #include<iostream> #include<algorithm> #include<cstdio> using namespace std; struc ...

  10. 【asp.net core】7 实战之 数据访问层定义

    0. 前言 在上一篇,我们搭建了一个项目框架,基本上是一个完整的项目.目前而言,大部分的应用基本都是这个结构.好的,不废话了,进入今天的议题:完成并实现数据层的基础实现. 1. 数据实体 通常情况下, ...