一 序
本文属于极客时间Elasticsearch核心技术与实战学习笔记系列。
二 分页
2.1 From / Size
- 默认情况下,查询按照相关度算分排序,返回前 10 条记录
- 容易理解的分页方案
- From : 开始位置
- Size:期望获取文档的总数
这里理解下:我只需要查询size条数据,而es则需要执行from+size条数据然后处理后返回。所以有很大的开销。
2.2 分布式系统中深度分页的问题
ES 天生就是分布式,查询信息,但是数据分别保存在多个分片,多台机器,ES 天生就需要满足排序的需要(按照相关性算分)
当一个查询:From = 990 ,Size =10
- 会在每个分片上先获取 1000 个文档。然后,通过 Coordinating Node 聚合所有结果。最后在通过排序选取前 1000 个文档
- 页数越深,占用内容越多。为了避免深度分页带来的内存开销。ES 有个设定,默认限定到 10000 个文档
2.3 demo
超出范围,会报错
3 Search After 避免深度分页的问题
- 避免深度分页的性能问题,可以实时获取下一页文档信息
- 不支持指定页数(From)
- 不能往下翻
- 第一步搜索需要指定 sort,并且保证值是唯一的(可以通过加入_id 保证唯一性)
- 然后使用上一次,最后一个文档的 sort 值进行查询
3.1 demo
数据准备:
#Scroll API
DELETE users
POST users/_doc
{"name":"user1","age":10}
POST users/_doc
{"name":"user2","age":11}
POST users/_doc
{"name":"user2","age":12}
POST users/_doc
{"name":"user2","age":13}
执行查询
针对返回的结果wkD_8HIBYdMHFwfFArwf,放到search_after。这样:
可以看到通过设置search_after的值,是可以避免深度分页的。
3.2Search After 是如何解决深度分页的问题
- 假设 Size 是 10
- 当查询 990 -1000
- 通过唯一排序值定位,将每次要处理的文档都控制在 10(避免性能开销)
看到这里,如果你熟悉MySQL,那么 自然也会想到MySQL的分页也可以采取类似的办法来避免offset导致的分页的尾页慢。
4 Scoll API
- 创建一个快照,有新的数据写入以后,无法被查找
- 每次查询后,输入上一次的 Scroll Id
4.1demo
数据准备,重新插入3条数据
我们使用scroll 生成快照,时间是5分钟
再插入一条记录:
吧第一次的scroll id拷出来,这样执行查询,最终只能查出3条记录。
{
"_scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAABjfgWNURvOERhUl9RV2U4U2stczl1RmZFQQ==",
"took" : 5,
"timed_out" : false,
"terminated_early" : true,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [ ]
}
}
文档4 是快照产生之后插入的,是无法被查到的。
5 不同的搜索类型和使用场景
Regular
- 需要实时获取顶部的部分文档。例如查询最新的订单
Scorll
- 需要全部文档,例如导出全部数据
Pagination
- From 和 Size
- 如何需要深度分页,则选用 Search After
***************************
理解很重要。