elasticsearch 分页查询实现方案——Top K+归并排序
elasticsearch 分页查询实现方案
1. from+size 实现分页
from表示从第几行开始,size表示查询多少条文档。from默认为0,size默认为10,
注意:size的大小不能超过index.max_result_window这个参数的设置,默认为10,000。
如果搜索size大于10000,需要设置index.max_result_window参数
PUT _settings
{
"index": {
"max_result_window": "10000000"
}
}
内部执行原理:
示例:有三个节点node1、node2、node3,每个节点上有2个shard分片
| node1 | node2 | node3 |
|---|---|---|
| shard1 | shard3 | shard5 |
| shard2 | shard4 | shard6 |
1.client发送分页查询请求到node1(coordinating node)上,node1建立一个大小为from+size的优先级队列来存放查询结果;
2.node1将请求广播到涉及到的shards上;
3.每个shards在内部执行查询,把from+size条记录存到内部的优先级队列(top N表)中;
4.每个shards把缓存的from+size条记录返回给node1;
5.node1获取到各个shards数据后,进行合并并排序,选择前面的 from + size 条数据存到优先级队列,以便 fetch 阶段使用。
各个分片返回给 coordinating node 的数据用于选出前 from + size 条数据,所以,只需要返回唯一标记 doc 的 _id 以及用于排序的 _score 即可,这样也可以保证返回的数据量足够小。
coordinating node 计算好自己的优先级队列后,query 阶段结束,进入 fetch 阶段。
from+size在深度分页时,会带来严重的性能问题:
CPU、内存、IO、网络带宽
数据量越大,越往后翻页,性能越低
2.scroll
可以把 scroll 理解为关系型数据库里的 cursor,因此,scroll 并不适合用来做实时搜索,而更适用于后台批处理任务,比如群发。
可以把 scroll 分为初始化和遍历两步,
初始化时将所有符合搜索条件的搜索结果缓存起来,可以想象成快照,
遍历时,从这个快照里取数据,也就是说,在初始化后对索引插入、删除、更新数据都不会影响遍历结果。
1.初始化:
POST http://192.168.18.230:9200/bill/bill/_search?scroll=3m
{
"query": { "match_all": {}},
"size": 10
}
参数 scroll,表示暂存搜索结果的时间
返回一个 _scroll_id,_scroll_id 用来下次取数据用
2.遍历:
POST http://192.168.18.230:9200/_search?scroll=3m
{
"scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAHRCFi1BLWIzSHdhUkl1cC1rcjBueVhJZUEAAAAAAAB0QRYtQS1iM0h3YVJJdXAta3IwbnlYSWVBAAAAAAAAdEQWLUEtYjNId2FSSXVwLWtyMG55WEllQQAAAAAAAHRDFi1BLWIzSHdhUkl1cC1rcjBueVhJZUEAAAAAAAB0RRYtQS1iM0h3YVJJdXAta3IwbnlYSWVB"
}
这里的 scroll_id 即 上一次遍历取回的 _scroll_id 或者是初始化返回的 _scroll_id,同样的,需要带 scroll 参数。
注意,每次都要传参数 scroll,刷新搜索结果的缓存时间。另外,不需要指定 index 和 type。
3.search_after
官网上的说明:
The Scroll api is recommended for efficient deep scrolling but scroll contexts are costly and it is not recommended to use it for real time user requests.
The search_after parameter circumvents this problem by providing a live cursor. The idea is to use the results from the previous page to help the retrieval of the next page.
Scroll 被推荐用于深度查询,但是contexts的代价是昂贵的,不推荐用于实时用户请求,而更适用于后台批处理任务,比如群发。
search_after 提供了一个实时的光标来避免深度分页的问题,其思想是使用前一页的结果来帮助检索下一页。
search_after 需要使用一个唯一值的字段作为排序字段,否则不能使用search_after方法
推荐使用_uid 作为唯一值的排序字段
GET twitter/tweet/_search
{
"size": 10,
"query": { "match_all": {}},
"sort": [
{"date": "asc"},
{"_uid": "desc"}
]
}
每一条返回记录中会有一组 sort values ,查询下一页时,在search_after参数中指定上一页返回的 sort values
GET twitter/tweet/_search
{
"size": 10,
"query": { "match_all": {}},
"search_after": [1463538857, "tweet#654323"],
"sort": [
{"date": "asc"},
{"_uid": "desc"}
]
}
注意:search_after不能自由跳到一个随机页面,只能按照 sort values 跳转到下一页
4.总结
- 深度分页不管是关系型数据库还是Elasticsearch还是其他搜索引擎,都会带来巨大性能开销,特别是在分布式情况下。
- 有些问题可以考业务解决而不是靠技术解决,比如很多业务都对页码有限制,google 搜索,往后翻到一定页码就不行了。
- scroll 并不适合用来做实时搜索,而更适用于后台批处理任务,比如群发。
- search_after不能自由跳到一个随机页面,只能按照 sort values 跳转到下一页。
转自:https://www.jianshu.com/p/171dcd33ab02
elasticsearch 分页查询实现方案——Top K+归并排序的更多相关文章
- elasticsearch 分页查询实现方案
1. from+size 实现分页 from表示从第几行开始,size表示查询多少条文档.from默认为0,size默认为10, 注意:size的大小不能超过index.max_result_wind ...
- 真正高效的SQLSERVER分页查询(多种方案)
Sqlserver数据库分页查询一直是Sqlserver的短板,闲来无事,想出几种方法,假设有表ARTICLE,字段ID.YEAR...(其他省略),数据53210条(客户真实数据,量不大),分页查询 ...
- Elasticsearch 分页查询
目录 前言 from + size search after scroll api 总结 参考资料 前言 我们在实际工作中,有很多分页的需求,商品分页.订单分页等,在MySQL中我们可以使用limit ...
- SQL分页查询,纯Top方式和row_number()解析函数的使用及区别
听同事分享几种数据库的分页查询,自己感觉,还是需要整理一下MS SqlSever的分页查询的. Sql Sever 2005之前版本: select top 页大小 * from 表名 where i ...
- Elasticsearch——分页查询From&Size VS scroll
Elasticsearch中数据都存储在分片中,当执行搜索时每个分片独立搜索后,数据再经过整合返回.那么,如果要实现分页查询该怎么办呢? 更多内容参考Elasticsearch资料汇总 按照一般的查询 ...
- ElasticSearch—分页查询
ElasticSearch查询—分页查询详解 Elasticsearch中数据都存储在分片中,当执行搜索时每个分片独立搜索后,数据再经过整合返回.那么,如何实现分页查询呢? 按照一般的查询流程来说,如 ...
- ElasticSearch——分页查询
前言 ElasticSearch实现分页查询,有3种方式,他们在数据查询中各自占据着不同的优势,因此在搜索引擎的数据分页过程中,如何更好地利用各自的优势来进行数据查询是一个非常重要的过程. 传统分页( ...
- Elasticsearch分页查询
global index global CLIENT index = "guajibao-ipused-2019.10.13" CLIENT = Elasticsearch(hos ...
- MySQL、Oracle和SQL Server的分页查询语句
假设当前是第PageNo页,每页有PageSize条记录,现在分别用Mysql.Oracle和SQL Server分页查询student表. 1.Mysql的分页查询: SELECT * FROM s ...
随机推荐
- 【转】SSH中 整合spring和proxool 连接池
[摘要:比来做的一个项目中应用到了毗邻池技巧,大概我们人人比拟认识的开源毗邻池有dbcp,c3p0,proxool.对那三种毗邻池来讲,从机能战失足率来讲,proxool轻微比前两种好些.本日我首要简 ...
- centos7 安装 PostgreSql
确定你是管理员,然后运行命令: yum -y install postgresql-server postgresql-contrib 初始化数据库 postgresql-setup initdb 启 ...
- SGU100
Read integers A and B from input file and write their sum in output file. Input Input file contains ...
- Vova and Trophies CodeForces - 1082B(思维题)
Vova has won nn trophies in different competitions. Each trophy is either golden or silver. The trop ...
- Scrapy爬虫框架示意图汇总
- Python os.listdir() 方法
概述 os.listdir() 方法用于返回指定的文件夹包含的文件或文件夹的名字的列表.这个列表以字母顺序. 它不包括 '.' 和'..' 即使它在文件夹中. 只支持在 Unix, Windows 下 ...
- odoo 二次开发小记-----不定时更新
一.odoo中 页面上字段变化引起其他字段范围变化-onchange @api.onchange('company_id') def onchange_parent_id(self): return ...
- 【Codeforces 459D】Pashmak and Parmida's problem
[链接] 我是链接,点我呀:) [题意] 定义两个函数 f和g f(i)表示a[1..i]中等于a[i]的数字的个数 g(i)表示a[i..n]中等于a[i]的数字的个数 让你求出来(i,j) 这里i ...
- 【codeforces 514C】Watto and Mechanism(字典树做法)
[题目链接]:http://codeforces.com/contest/514/problem/C [题意] 给你n个字符串; 然后给你m个询问;->m个字符串 对于每一个询问字符串 你需要在 ...
- App的登陆注册接口安全设计
最近一APP产品,我担任的主要模块之一是后台登录注册模块的接口开发.基本完成,就说说并记录一下关于登录注册接口的一些东西,因为也涉及到接口的安全方面的问题. 1.先一般的app的登录注册接口安全设计上 ...