5.4 分页 (Pagination) Elasticsearch 分页 (Pagination) 在 Elasticsearch 中,分页是指将搜索结果分成多个页面显示,以便用户可以逐步浏览大量数据。 Elasticsearch 提供了多种分页方法,可以根据不同的需求选择合适的方式。 和 这是最基本也是最常用的分页方式。 : 指定从哪个文档开始返回结果(偏移量)。 : 指定每个页面返回的文档数量。 代码示例: 详解: 上述查询会返回 索引中的前 10 个文档。 要获取第二页,可以将 设置为 10, 保持不变: 优点: 简单易用,适用于大多数场景。 缺点: 当 值很大时,性能会下降。 Elasticsearch 需要跳过大量的文档才能找到起始位置,这会消耗大量的 CPU 和内存资源。
在 Elasticsearch 中,分页是指将搜索结果分成多个页面显示,以便用户可以逐步浏览大量数据。 Elasticsearch 提供了多种分页方法,可以根据不同的需求选择合适的方式。
from 和 size这是最基本也是最常用的分页方式。
from: 指定从哪个文档开始返回结果(偏移量)。
size: 指定每个页面返回的文档数量。
代码示例:
GET /your_index/_search { "from": 0, // 从第一个文档开始(相当于第一页) "size": 10, // 每页返回 10 个文档 "query": { "match_all": {} } }
详解:
上述查询会返回 your_index 索引中的前 10 个文档。
要获取第二页,可以将 from 设置为 10,size 保持不变:
GET /your_index/_search { "from": 10, // 从第 11 个文档开始(相当于第二页) "size": 10, // 每页返回 10 个文档 "query": { "match_all": {} } }
优点:
缺点:
当 from 值很大时,性能会下降。 Elasticsearch 需要跳过大量的文档才能找到起始位置,这会消耗大量的 CPU 和内存资源。 例如,要获取第 1000 页(每页 10 个文档),from 将是 9990。 Elasticsearch 需要检索并跳过前 9990 个文档,这会变得非常低效。
不适用于深度分页(例如,超过 10000 个文档)。 Elasticsearch 默认限制了 from + size 的最大值,以防止内存溢出。
search_aftersearch_after 是一种更高效的分页方式,尤其是在需要深度分页时。 它使用前一页最后一个文档的排序值作为起始点,而不是像 from 那样使用偏移量。
代码示例:
GET /your_index/_search { "size": 10, "query": { "match_all": {} }, "sort": [ { "_id": "asc" } // 必须指定排序字段,且需要保证排序字段的唯一性 ] }
上述查询返回第一页数据,假设最后一篇文档的 _id 是 AWaJkGOK0qumFvj-H9vL,则获取第二页数据的查询如下:
GET /your_index/_search { "size": 10, "query": { "match_all": {} }, "sort": [ { "_id": "asc" } ], "search_after": [ "AWaJkGOK0qumFvj-H9vL" // 上一页最后一个文档的排序值 ] }
详解:
sort: 必须指定排序字段,且需要保证排序字段的唯一性。 通常使用 _id 或其他具有唯一性的字段。
search_after: 是一个数组,包含上一页最后一个文档的排序值。 数组中值的顺序必须与 sort 中字段的顺序一致。
第一次查询时,不需要 search_after 参数。
每次查询后,需要从结果中提取最后一个文档的排序值,并在下一次查询中使用。
优点:
性能优于 from 和 size,尤其是在深度分页时。 search_after 不需要跳过大量的文档,而是直接从指定的排序值开始检索。
适用于实时滚动浏览数据。
缺点:
需要指定排序字段,且排序字段需要保证唯一性。
不适用于随机访问页面,只能按顺序浏览。
如果数据在分页期间发生变化,可能会导致结果不一致。
注意事项:
Scroll API 适用于需要一次性获取大量数据,且不需要实时性的场景,例如数据导出、数据备份等。 它会创建一个快照,并在快照上进行迭代,因此即使数据在滚动期间发生变化,也不会影响结果。
代码示例:
POST /your_index/_search?scroll=1m // 1m 表示 scroll 上下文保持 1 分钟 { "size": 1000, "query": { "match_all": {} } }
上述查询会返回一个 scroll_id,用于后续的滚动请求。
POST /_search/scroll { "scroll": "1m", "scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBZXF0ZHRvX3F1ZXJ5DnF1ZXJ5VGhlbkZldGNoAwAAAAAAABkUFkZlT0F0V1J3UE1rV1h3c3JvT2J4dwAAAAAAAAAZFBZGZU9BdFdSd1BNa1dYd3Nyb09ieHcAAAAAAAAAGRQWRmVPT0F0V1J3UE1rV1h3c3JvT2J4dwAAAAAAAAAZFBZGZU9BdFdSd1BNa1dYd3Nyb09ieHcAAAAAAAAAGRQWRmVPT0F0V1J3UE1rV1h3c3JvT2J4dw==" }
详解:
scroll: 指定 scroll 上下文的保持时间。 例如,1m 表示保持 1 分钟。 应该足够长,以便完成所有滚动请求。
scroll_id: 第一次查询返回的 scroll_id,用于后续的滚动请求。
每次滚动请求都会返回一个新的 scroll_id,应该在下一次请求中使用。
当没有更多数据时,滚动请求将返回一个空的 hits 数组。
完成滚动后,应该清除 scroll 上下文,释放资源:
DELETE /_search/scroll { "scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBZXF0ZHRvX3F1ZXJ5DnF1ZXJ5VGhlbkZldGNoAwAAAAAAABkUFkZlT0F0V1J3UE1rV1h3c3JvT2J4dwAAAAAAAAAZFBZGZU9BdFdSd1BNa1dYd3Nyb09ieHcAAAAAAAAAGRQWRmVPT0F0V1J3UE1rV1h3c3JvT2J4dwAAAAAAAAAZFBZGZU9BdFdSd1BNa1dYd3Nyb09ieHcAAAAAAAAAGRQWRmVPT0F0V1J3UE1rV1h3c3JvT2J4dw==" }
优点:
适用于一次性获取大量数据,且不需要实时性的场景。
性能优于 from 和 size,尤其是在需要获取所有数据时。
可以保证数据的一致性,即使数据在滚动期间发生变化。
缺点:
不适用于实时滚动浏览数据。
需要手动管理 scroll 上下文。
会占用服务器资源,应该及时清除 scroll 上下文。
| 特性 | from 和 size |
search_after |
Scroll API |
|---|---|---|---|
| 适用场景 | 常规分页 | 深度分页 | 数据导出/备份 |
| 性能 | 较低 (深度分页) | 较高 | 较高 |
| 实时性 | 较高 | 较高 | 较低 |
| 数据一致性 | 较低 (数据变化) | 较低 (数据变化) | 较高 |
| 易用性 | 简单 | 较复杂 | 较复杂 |
| 是否随机访问 | 是 | 否 | 否 |
Elasticsearch 提供了多种分页方式,可以根据不同的需求选择合适的方式。
from 和 size 适用于常规分页,简单易用,但性能较低,不适用于深度分页。
search_after 适用于深度分页,性能较高,但需要指定排序字段,且不适用于随机访问页面。
Scroll API 适用于一次性获取大量数据,且不需要实时性的场景,性能较高,可以保证数据的一致性,但需要手动管理 scroll 上下文。
在实际应用中,应该根据具体的业务场景和数据量选择合适的分页方式,并进行性能测试,以确保分页功能的效率和稳定性。