深度分页问题

简介: 深度分页问题

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

问题描述

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

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

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

http

复制代码

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是一种用于处理大量数据的分批次查询机制。

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

http

复制代码

# 设置一个滚动搜索
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适用于持久化保存查询状态,并支持随时获取下一页结果。

http

复制代码

# 获得前 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需要设置滚动时间间隔,超过该时间将失去滚动上下文。


相关文章
|
前端开发 Java 测试技术
通用分页【上】
JUnit是流行的、开源的Java单元测试框架,它提供了一种简单而强大的方式来测试Java应用程序中的单元代码。JUnit测试通常涉及创建和运行测试用例,而测试用例是一组独立的测试步骤,用于验证代码是否按照预期工作。JUnit测试通常分为以下四个步骤:定义测试用例:定义每个测试方法所需的输入参数以及期望的输出结果;编写测试代码:编写测试方法并使用断言(Assertion)来验证代码是否按照预期工作;运行测试用例:通常使用JUnit测试浏览器或者其他测试工具来运行测试用例;查看测试结果。
|
算法 JavaScript Java
通用分页【下】(将分页封装成标签)
调试()是指在软件开发过程中,通过识别、定位和解决程序错误或问题的过程。调试的目的是找出代码中的错误、异常或不正常的行为,并修复它们,以确保程序能够按照预期的方式运行。调试是一个重要的开发技巧,可以帮助开发人员理解程序的执行过程、找出错误的原因,并从中学习和改进。调试可以使用不同的工具和技术来辅助,例如打印输出、日志记录、调试器(debugger)等。调试是开发过程中不可或缺的一部分,可以帮助开发人员提高代码质量、加快解决问题的速度,并优化程序的性能和可靠性。
|
前端开发 数据管理 Java
通用分页(下)
通用分页(下)
43 0
|
7月前
|
存储 SQL 前端开发
解决深度分页问题
解决深度分页问题
|
Java 数据库
通用分页之详解】
通用分页之详解】
41 1
|
前端开发 Java UED
通用分页集模糊,全部查询,分页查询为一体(2)演示,优化上篇通用查询分页
通用分页集模糊,全部查询,分页查询为一体(2)演示,优化上篇通用查询分页
|
7月前
|
前端开发 关系型数据库 MySQL
通用分页详解
通用分页详解
61 0
通用分页(后台分页)
通用分页(后台分页)
58 0
|
前端开发
通用分页02(前台分页)
通用分页02(前台分页)
61 0
|
SQL 存储 Java
通用分页(上)
通用分页(上)
52 0