雪狼网站系统,如何做 行业社交类网站,桂林漓江,如何设置公司网站从数据集中获取数据时分页是绕不开的操作#xff0c;一下子从数据集中获取过多的数据可能会造成系统抖动、占用带宽等问题。特别是进行全文搜索时#xff0c;用户只关心相关性最高的那个几个结果#xff0c;从系统中拉取过多的数据等于浪费资源。
ES提供了3种分页方式…从数据集中获取数据时分页是绕不开的操作一下子从数据集中获取过多的数据可能会造成系统抖动、占用带宽等问题。特别是进行全文搜索时用户只关心相关性最高的那个几个结果从系统中拉取过多的数据等于浪费资源。
ES提供了3种分页方式
from size: 最普通、简单的分页方式但是会产生深分页的问题search after: 解决深分页的问题但只能一页页地往下翻不支持跳到指定页数scroll Api: 会创建数据快照无法检索新写入的数据适合对结果集进行遍历的时候
这3种方式的分页操作都有其优缺点适合不同的场合使用。今天我们就来学习这3种分页方式但除了学习这3种分页方式外我们还会介绍ES新引入的特性Point In Time看看如何使用Point In Timesearch after的方式来代替scroll Api进行大量数据的导出 from size 分页操作与深分页问题
在我们检索数据时系统会对数据相关性算分进行排序然后默认返回前10条数据。我们可以使用from size来指定获取哪些数据。其使用示例如下
# 简单的分页操作
GET books/_search
{from: 0, # 指定开始位置size: 10, # 指定获取文档个数query: {match_all: {}}
}如上示例使用“from”指定获取数据的开始位置使用“size”指定获取文档带的个数
但当我们将from设置大于10000或者size设置大于10001的时候这个查询将会报错
# 返回结果中的部分错误信息
......
root_cause : [{type : illegal_argument_exception,reason : Result window is too large, from size must be less than or equal to: [10000] but was [10001]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting.}
],
type : search_phase_execution_exception,
reason : all shards failed,
phase : query,
grouped : true,
......从报错信息可以看出我们要获取的数据集合太大了系统拒绝了我们的请求。我们可以使用“index.max_result_window”配置项设置这个上限
PUT books/_settings
{index: {max_result_window: 20000}
}如上示例我们设置了这个上限为20000。虽然使用这个配置有时候可以解决燃眉之急但是这个上限设置过大的情况下会产生非常严重的问题因为ES会存在深分页的问题
那为什么时深分页和为什么会产生深分页的问题那如上图ES把数据保存在3个主分片中当使用from90 和size10进行分页的时候ES会从每个分片中分别获取100个文档然后把这300个文档在汇聚到协调节点中进行排序最后选出排序后的前100个文档返回第90到99的文档
可以看到当页数变大发生了深分页的时候在每个分片中获取的数据越多消耗的资源就越多。并且如果分片越多汇聚到协调节点的数据越多最终协调到协调节点的文档数为shard_acount *(from size) search after
使用search after api可以避免产生深分页的问题不过 search after 不支持跳转到指定页面只能一页页的往下翻
使用 search after接口分为两步
在sort中指定需要排序的字段并且保证其值的唯一性可以使用文档的id在下一次查询时带上返回结果的最后一个文档的sort值进行访问
search after的使用示例如下
# 第一次调用 search after
POST books/_search
{size: 2,query: { match_all: {} },sort: [{ price: desc },{ _id: asc }]
}# 返回结果
hits : [{_id : 6,_source : {book_id : 4ee82467,price : 20.9},sort : [20.9, 6]},{_id : 1,_source : {book_id : 4ee82462,price : 19.9},sort : [19.9, 1]}
]如上示例在第一次调用search after时指定了sort的值并且sort中指定了price 倒序排序。为了保证排序的唯一性我们指定了文档_id作为唯一值
可以看到第一次调用的返回结果除了文档的信息外还有sort相关的信息在下一次调用的时候需要带上最后一个文档的sort值示例中其值为[19.9, “1”]。
下面的示例是第二次调用search after 接口进行翻页操作
# 第二次调用 search after
POST books/_search
{size: 2,query: {match_all: {}},search_after:[19.9, 1], # 设置为上次返回结果中最后一个文档的 sort 值sort: [{ price: desc },{ _id: asc }]
}如上示例进行翻页操作的时候在search after字段中设置上一次返回结果中最后一个文档的sort值并且保持sort的内容不变
那为啥search after不会产生深度分页的问题那其关键就是sort中指定的唯一排序值如上图因为有了唯一的排序值做保证所以每个分片只需要返回比sort中唯一值大的size个数据即可。例如上一次的查询返回的最后一个文档的sort为a那么这一次查询只需要在分片123中返回size个排序比a大的文档协调节点汇总这些数据进行排序后返回size个结果给客户端
而from size的方式因为没有唯一值所以没法保证每个分片上的排序就是全局的排序必须把每个分片的fromsize个数据汇总到协调节点进行排序处理导致出现了深分页的问题
因为sort的值是根据上一次请求结果来设置的所以search after不支持跳转到指定的页数甚至不能返回前一页只能一页页往下翻。当我们可以结合缓存中间件把每页返回的sort值缓存下来实现往前翻页的功能 scroll Api
当我们相对结果集进行排序的时候例如做全量数据导出时可以使用scroll Api。scroll Api会创建数据快照后续的访问将会基于这个快照来进行所以无法检索新写入的数据。scroll API 的使用示例如下
# 第一次使用 scroll API
POST books/_search?scroll10m
{query: {match_all: {}},sort: { price: desc }, size: 2
}# 结果
{_scroll_id : FGluY2x1ZGVfY29udGV4dF9......,hits : {hits : [{_id : 6,_source : {book_id : 4ee82467,price : 20.9}},......]}
}
如上示例在第一次使用scroll Api需要初始化scroll 搜索并且创建快照使用scroll查询参数指定本次“查询上下文快照”的有效时间本示例中为10分钟。
其返回的结果中除了匹配文档的列表外还有_scroll_id, 我们需要在翻页的请求带上这个_scroll_id:
# 进行翻页
POST /_search/scroll
{scroll : 5m, scroll_id : FGluY2x1ZGVfY29udGV4dF9......
}