深度分页问题

182 阅读4分钟

一起学Elasticsearch系列-深度分页问题 (qq.com)

问题描述

ES的深度分页问题指,在大数据集和大页数的情况下,通过持续向后翻页来获取查询结果的一种性能问题。

当页码非常高时,ES需要遍历大量文档才能找到正确的分页位置,导致性能和查询速度变慢。

但是当我们查询的数据页数特别大, from + size大于 10000的时候,就会出现问题。

GET my_index/_search  
{  
  "from": 10000,  
  "size": 5  
}

这个查询会产生报错:请求中的偏移量(from)加上大小(size)超过了索引级别参数 10000的最大值

为什么会有这个限制呢?深度分页问题又和这有什么关系?

深度分页的性能问题和危害

我们要明确,分布式系统都面临着同一个问题,数据的排序不可能在同一个节点完成

如果只是单节点,那么排序操作非常简单,只需要在排序后从前向后取出对应数据即可。

但是如果在多节点的背景下,情况截然不同。因为每个节点的数据是均匀分布的,所以需要对每个节点进行排序,取出所有可能的文档然后合并在一起再次排序。

这个过程会随着分页的深度、分片的数量成倍的增加。

举个例子:

我们要找出全球所有人中,排名前第 10000 到 10005 的评分最高的人。每个国家都有一个ES记录所有人的评分数据。

为了找到正确的结果,我们需要在全球所有国家的ES上找出排名前 10005 的,然后再把所有国家的结果合并起来,再找出前 10005 名,最后取出那五个人

每次有序的查询都会在每个分片中执行单独的查询,然后进行数据的二次排序,而这个二次排序的过程是发生在Heap中的,也就是说当你单次查询的数量越大,那么堆内存中汇总的数据也就越多,对内存的压力也就越大

单次查询的数据量取决于你查询的是第几条数据而不是查询了几条数据,如果查询的数据排序越靠后,就越容易导致OOM(Out Of Memory)情况的发生。

所以,这也是为什么ES需要设置索引级别参数 10000的最大值

解决方案

Scroll Search

Scroll Search是一种用于处理大量数据的分批次查询机制。

通过使用滚动搜索,可以在不影响性能的情况下逐批次地获取结果集。

# 设置一个滚动搜索
GET /exam_info/_search?scroll=5m  
{  
  "size": 100,  
  "sort": [  
    { "score": "desc" }  
  ]  
}

# 获取下一个搜索结果
# scroll_id 从上一个得到
GET /_search/scroll  
{  
  "scroll": "5m",  
  "scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAACsFlRlQjNqSVh0VzIwdXk4UnhOTmdSc2cAAAAAADFLW0xjb3VkT1dHcG9uejZtZURxS3oxMw=="  
}

滚动搜索是一种方便的分批次查询机制,但无法长期保存查询结果或索引状态

原因是滚动搜索是一种临时的、游标式的查询机制,仅用于获取大量数据的分批次结果。

它并不会保留索引状态或缓存查询结果,主要用于处理大量数据的查询,以提高性能和效率。

当执行滚动搜索时,Elasticsearch会创建一个滚动上下文(scroll context),该上下文存储了关于初始查询的一些信息,包括查询条件、排序方式等。然后,每次使用滚动上下文来获取下一批结果时,Elasticsearch都会根据该上下文重新执行查询以返回新的结果。这样可以确保在整个滚动搜索过程中,能够按顺序逐步获取完整的结果集。

超时后,搜索上下文会自动删除。保持Scrolls打开是有代价的,因此一旦不再使用就应明确清除Scroll上下文。

Search After

Search After 是一种基于游标的分页查询机制,用于获取大量数据的连续结果。

与滚动搜索不同,Search After适用于持久化保存查询状态,并支持随时获取下一页结果。

# 获得前 100 个结果
GET /exam_info/_search  
{  
  "size": 100,  
  "sort": [  
    { "score": "desc" }  
  ]  
}

# 获得在前面排序下来的第 97 号记录,后面的 100 个结果
GET /exam_info/_search  
{  
  "size": 100,  
  "sort": [  
    { "score": "desc" }  
  ],  
  "search_after": [97]  
}

小结

Search After 和 Scroll Search 的主要区别如下:

  • 结果排序:Search After依赖排序字段进行分页,需要指定相应的排序方式。而Scroll Search可以根据查询条件对结果进行排序。

  • 时间限制:Search After没有时间限制,可按需获取结果。而Scroll Search需要设置滚动时间间隔,超过该时间将失去滚动上下文。