创作人:张超
在查询场景中,从 Elasticsearch 中取得结果,根据不同场景,有多种不同的方式。
通过 from 、size 进行分页通过 scroll 拉取大量数据通过 search_after 拉取大量数据每种方式有其各自的使用场景,或者说他们是为了解决某种场景而设计的。
from + size搜索引擎的场景,类似 google 搜索,翻页操作一般是人为触发的,并且人的行为一般不会翻页太多,from+size 这种最经典的翻页模式是为了解决用户对于 TopN 的需求,用户希望找到 TopN 个最匹配的文档。其使用方式类似 SQL 中的 LIMIT关键字,Elasticserach 使用 from 和 size 两个参数来控制翻页:
size: 要返回的结果数量,默认为 10from: 要跳过的结果数量,默认为 0如果每页显示 5 条结果,下面的命令可以得到 1-3 页的结果:
GET /_search?size=5 GET /_search?size=5 from=5 GET /_search?size=5 from=10
分页搜索实现方式是:
每个分片各自查询的时候先构建 from+size 的优先队列,然后将所有的文档 ID 和排序值返回给协调节点。协调节点创建 size 为 number_of_shards * (from + size) 的优先队列,对数据节点的返回结果进行合并,取全局的 from+size 返回给客户端这种工作模式的主要代价在于,协调节点需要等待所有分片返回结果,然后再全局排序。因此会创建非常大的优先队列,需要控制分页的深度,Elasticsearch 默认最多返回 10000 个文档。但是有些时候,用户需要遍历取回所有文档,甚至可以不关心排序。在数据库中取回全部结果可以使用游标查询的方式,类似的概念在 Elasticsearch 中叫做 scroll。
scrollscroll 可以用于拉取全量数据,他的工作模式不需要像 from + size 一样全局排序,因此没有深分页的代价,例如 reindex 本质上就是 scroll+bulk。使用 scroll 可以简单的在查询语句中添加 scroll 参数:
POST /my-index-000001/_search?scroll=1m
上面的查询语句会返回一个 ID,后面可以根据这个 ID 顺序拉取结果:
POST /my-index-000001/_search/scroll "scroll" : "1m", "scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ==" }
Elasticsearch 将查询后的上下文保存在服务端,因此客户端可以依据这个 scroll_id 依次获取后续的数据。
这个上下文也必然有一个生命周期,因为他会一直占用服务端资源。在这个例子中,我们设置 scroll 窗口保存 1 分钟的时间。1 分钟之内,你都可以使用 scroll_id 来拉取数据。当然,你也可以在拉取完成之后根据 scroll_id 手工清理上下文。
search_after如果说 scroll 是把上下文保存在服务端,而 search_after 要求数据中存在一个无重复,可以用于排序的字段,需要客户端每次传入上次查到的最后结果,然后获取其随后的数据。
由于随后的请求每次都是查询出来的,如果数据发生变化,就可能出现跨页面结果不一致的情况,为了防止这种情况,需要在请求中加一个参数来设置当前的索引状态保留时间。
POST /my-index-000001/_pit?keep_alive=1m
PIT 是 point in time 的简写,他是一个轻量级的视图。上述请求返回一个 ID:
{ "id": "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA==" }
随后的请求中你需要带上他。可以通过下面的方式,获取第一页的结果,其中的特别之处在于,要指定进行排序的字段:
GET /_search "size": 10000, "query": { "match" : { "user.id" : "elkbee" "pit": { "id": "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA==", "keep_alive": "1m" "sort": [ {"@timestamp": "asc"}
在返回结果中,会携带 sort 字段的值,
{ "hits" : { "hits" : [ "sort" : [ 4294967298
你需要在下次请求的时候带上他:
GET /_search "size": 10000, "query": ... "pit": { "id": ... "keep_alive": ... "sort": [ {"@timestamp": "asc"} "search_after": [ 4294967298
类似 scroll,pit 请求返回的 ID 也可以手工清理。
最后我们总结一下每种分页方式的特点:
from+size 支持跳页,不适合深分页;scroll 不支持跳页,适合拉取大量数据,不适合大量并发search_after 不支持跳页,适合拉取大量数据Scroll 和 search_after 都可以用于深分页,search_after 需要提供一个主键字段进行排序,默认为 _shard_doc,它是 shard index 与 Lucene 内部 ID 的组合值。在服务端保存的上下文要比 scroll 小,目前官方推荐使用 search_after 代替 scroll。
大数据市场如今正在呈爆炸式增长。根据调研机构Markets and Markets公司的调查,...
【51CTO.com快译】 数据分析是对数据进行判断、细化、更改和建模的过程,目的是...
案例背景 永安稻香小镇的体验式数字农业基地是余杭街道依托“阿里以西10分钟”的...
阿里巴巴、腾讯、支付宝、网易、IBM、谷歌、京东、 百度、滴滴等一线互联网公司...
人脸识别 是目前商业应用最成熟、最广泛的人工智能技术之一,成为开发者、企业接...
操作场景 您可以删除不需要的私有镜像。 删除私有镜像后,将无法找回,请谨慎操...
【51CTO.com快译】不知道您是否听说过软件架构师最讨厌意大利面这个梗?它是指软...
本月DataWorks产品月刊为您带来 产品活动 1.参与阿里云DataWorks问卷调研 (Aliyu...
公司介绍 长沙营智信息技术有限公司旗下易撰网,2017年10月份上线以来,基于数据...
大家在开发Python的过程中,一定会遇到很多反斜杠的问题,很多人被反斜杠的数量...