淘先锋技术网

首页 1 2 3 4 5 6 7

一 序

  本文属于极客时间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

***************************

理解很重要。