一步一步理解elasticsearch分页查询

2024-08-01 17:59:59 浏览数 (3)

一、分页查询方式

在应用中经常需要用到分页查询来访问数据,同时由于分页查询产生相应的性能问题也比较多,通过梳理使用分页查询的使用方式,避免性能问题。

分页查询有以下几中方式:

  • from ... size
  • search after
  • scroll
  • pit

二、分页查询的使用方式

示例数据

代码语言:txt复制
DELETE my_index

POST /_bulk
{ "index": { "_index": "my_index", "_id": "1" } }
{ "timestamp": "2024-08-01T00:00:00", "user_id": 1, "message": "Message 1" }
{ "index": { "_index": "my_index", "_id": "2" } }
{ "timestamp": "2024-08-01T00:01:00", "user_id": 2, "message": "Message 2" }
{ "index": { "_index": "my_index", "_id": "3" } }
{ "timestamp": "2024-08-01T00:02:00", "user_id": 3, "message": "Message 3" }
{ "index": { "_index": "my_index", "_id": "4" } }
{ "timestamp": "2024-08-01T00:03:00", "user_id": 4, "message": "Message 4" }
{ "index": { "_index": "my_index", "_id": "5" } }
{ "timestamp": "2024-08-01T00:04:00", "user_id": 5, "message": "Message 5" }
{ "index": { "_index": "my_index", "_id": "6" } }
{ "timestamp": "2024-08-01T00:05:00", "user_id": 6, "message": "Message 6" }
{ "index": { "_index": "my_index", "_id": "7" } }
{ "timestamp": "2024-08-01T00:06:00", "user_id": 7, "message": "Message 7" }
{ "index": { "_index": "my_index", "_id": "8" } }
{ "timestamp": "2024-08-01T00:07:00", "user_id": 8, "message": "Message 8" }
{ "index": { "_index": "my_index", "_id": "9" } }
{ "timestamp": "2024-08-01T00:08:00", "user_id": 9, "message": "Message 9" }
{ "index": { "_index": "my_index", "_id": "10" } }
{ "timestamp": "2024-08-01T00:09:00", "user_id": 10, "message": "Message 10" 
}

1、from 和 size

代码语言:txt复制
POST /my_index/_search 
{
  "from": 3,
  "size": 3,
  "sort": [
    {"timestamp": "asc"}
  ]
}

特点:

  • 动态分页,用户需要跳转到特定页。
  • 简化实现,特别是数据集较小或临时查询。
  • 排序字段非唯一,重复值较多。
  • 需要跳过大量记录,但只返回少量结果。

2、search after

代码语言:txt复制
第一次查询
POST /my_index/_search 
{
  "size": 3,
  "sort": [{"timestamp": "asc"}, {"user_id": "asc"}]
}
#第二次查询使用第一次查询的timestamp结果和user_id结果
POST /my_index/_search 
{
  "size": 3,
  "sort": [{"timestamp": "asc"}, {"user_id": "asc"}],
  "search_after": ["2024-08-01T00:02:00", 3]
}
基本原理就是每次查询取后面的排序字段,进行一轮查询,这个通常用来替换from,size的深度分页中from比较大的查询。
但是要求是排序字段要唯一,不能存在多个值。

特点:

  • 深度分页,查询结果较大。
  • 避免性能问题,特别是当 from 值较大时。
  • 需要稳定的排序结果,每次查询都依赖上一次查询的排序值。
  • 实时性要求高,确保每次查询都能反映最新数据

3、 scroll

代码语言:txt复制
POST /my_index/_search?scroll=2m 
{
  "size": 3,
  "sort": [{"timestamp": "asc"}, {"user_id": "asc"}]
}
POST /_search/scroll
{
  "scroll": "2m",
  "scroll_id": "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFkNnSWRNQTc0UWtPZnh2eEZmdFl0dncAAAAAACzXABZ2d2pCVlFINlJiQ0oyVDhaUkJlUWxR"
}
注意点:
1、在scroll=2m的周期内,数据有上下文的参与,在这个周期内数据是一致的。
2、_reindex接口内部就是使用scroll方式分批取数据。
3、由于要维护上下文,会占用一部分内存

特点:

  • 需要处理大规模的结果集
  • 一致性要求高
  • 需要进行长时间的批量数据处理。

4、pit

代码语言:txt复制
POST /my_index/_pit?keep_alive=2m

POST /_search
{
  "size": 3,
  "sort": [{"timestamp": "asc"}, {"user_id": "asc"}],
  "pit": {"id": "4YyPBAEIbXlfaW5kZXgWRTdqdDlNQXlTSVcwdnlISTR6anFzZwAWdndqQlZRSDZSYkNKMlQ4WlJCZVFsUQAAAAAAACzZThZDZ0lkTUE3NFFrT2Z4dnhGZnRZdHZ3AAEWRTdqdDlNQXlTSVcwdnlISTR6anFzZwAA"}
}

三、分页查询产生的常见问题

1、内存溢出

原因:滚动查询(scroll)会在内存中保持一个快照,如果数据量太大或 scroll 持续时间过长,可能会导致内存溢出。

解决办法:

减少单次请求的 size: 将每次请求的数据量减少。

优化查询: 使用过滤条件来减少查询结果集。

增加集群节点: 提升集群的资源配置。

2、scroll超时

滚动上下文在指定时间后会过期,如果在此时间内没有进行下一次请求,滚动上下文会被删除。

解决办法:

延长 scroll 时间: 根据需要延长 scroll 的保留时间。

及时获取下一批数据: 确保在 scroll 时间内获取下一批数据。

3. search_context_missing_exception

原因:滚动上下文已过期或不存在。

处理办法

检查 scroll 保留时间: 确保在 scroll 时间内发起请求。

使用 Point in Time (PIT): 作为替代方案,可以使用 PIT 来处理长时间的查询。

0 人点赞