-
From+Size
1.1 基本用法
查出第 6~8 笔数据GET /my_index/_search { "from": 5, "size": 3 }
- from:表示记录开始的顺序,默认0
- size:表示取回几笔数据,默认10
- from+size 默认不能超过10000,可以通过修改索引参数index.max_result_window调整
1.2 基本原理
- 协调节点将查询请求发送给所有分片
- 各分片收到请求后,查出 from + size 的数据,并返回给协调节点。例如:当前请求是查询第5~10笔数据,from + size = 10,因此每个分片都要返回排序后的前10笔数据
- 协调节点将收到的数据进行合并,重新排序,然后返回指定的size分页数据给客户端
1.3 存在的问题
- 深分页的情况下,也就是from + size 值特别大,可能会造成慢查询。因为每个节点都需要返回 from + size 的排序数据,然后最终还需要合并以及排序,就算没有内存溢出,对CPU和IO也有巨大影响。
为了解决这种问题,ES官方推荐使用 scroll 或者 search_after
-
Scroll
2.1 基本用法
第一步,初始化 scroll ,并获取第一批数据:POST /my_index/_search?scroll=5m { "size":2, "query": { "match_all": {} }, "sort": [ { "num": { "order": "asc" } } ] }
- scroll=5m:指定查询上下文的有效期,这边设置为5分钟
- size:指定初始化分页大小,这边设置2
- sort:排序
返回值如下:
{
"_scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFDFaQ3hQblVCNEZuWkdyWGFCcDFnAAAAAADGUE0WclVEQkh0VUlSWnFFM05QUEJaMU5Sdw==",
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 10,
"relation" : "eq"
},
"max_score" : null,
"hits" : [
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "pJBvPnUB4FnZGrXaoStR",
"_score" : null,
"_source" : {
"num" : 1
},
"sort" : [
1
]
},
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "pZBvPnUB4FnZGrXaoStR",
"_score" : null,
"_source" : {
"num" : 2
},
"sort" : [
2
]
}
]
}
}
- 注意:返回值的第一项是_scroll_id,后面的每一步查询都需要传递该参数
第二步,获取下一页数据:
POST /_search/scroll
{
"scroll": "5m",
"scroll_id": "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFDFaQ3hQblVCNEZuWkdyWGFCcDFnAAAAAADGUE0WclVEQkh0VUlSWnFFM05QUEJaMU5Sdw=="
}
- scroll:指定查询上下文的有效期,这边仍然设置为5分钟。注意:这步执行完毕后,查询上下文的有效期将重新计算。可以理解为scroll有效期的设置指的是2次查询的时间间隔,如果超过该有效期没有任务查询发生,那将会失效。
- scroll_id:传递最近一次查询返回的_scroll_id
2.2 基本原理
- scroll 初始化会返回所有符合条件的数据,并形成一份快照数据
- 每次获取分页数据,都会以类似游标的方式读取该快照
快照的有效期由scroll参数指定,每次查询重新传递scroll参数,会刷新有效期 - 快照形成后,ES索引数据的更新都不会被 scroll 读取到,这边读取的仍然是快照生成时的数据。因此,不适用于实时数据要求非常高的场景。
2.3 存在的问题
- 不建议同时打开大量的 scroll 上下文,因为在 scroll 有效期到达之前,都会占用一定的内存空间。官方默认同时打开的 scroll 数量是500,可以通过 search.max_open_scroll_context参数调整
- scroll 上下文指的是第一次初始化形成的快照,后续基于该上下文的查询都不会查到最新数据。因此不适用于实时性高的场景。
为了避免这些问题,官方推出另一个查询方式:Search After
-
Search After
3.1 基本用法
第一步:构造数据:
第二步:查出第1页数据,按num+name进行组合排序GET test_json/_search { "query": { "bool": { "filter": [ { "term": { "status": "309" } } ] } }, "size": 2, "from": 0, "sort": [ { "_id": { "order": "desc" } } ] }
结果如下:
{ "took" : 2, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 181, "relation" : "eq" }, "max_score" : null, "hits" : [ { "_index" : "test_json", "_type" : "_doc", "_id" : "yjqdNHgBXcRYjwgstiZS", "_score" : null, "_source" : { "size" : 0, "clientip" : "127.0.0.1", "responsetime" : 0.0, "domain" : "localhost", "host" : "127.0.0.1", "status" : "309", "upstreamtime" : "-", "url" : "/index.html", "xff" : "-", "http_host" : "localhost", "@timestamp" : "2019-10-12T10:41:48.000Z", "referer" : "-", "@version" : "1", "path" : "/opt/logs/access.log", "upstreamhost" : "-" }, "sort" : [ "yjqdNHgBXcRYjwgstiZS" ] }, { "_index" : "test_json", "_type" : "_doc", "_id" : "yTqdNHgBXcRYjwgstiZS", "_score" : null, "_source" : { "size" : 0, "clientip" : "127.0.0.1", "responsetime" : 0.0, "domain" : "localhost", "host" : "127.0.0.1", "status" : "309", "upstreamtime" : "-", "url" : "/index.html", "xff" : "-", "http_host" : "localhost", "@timestamp" : "2019-10-12T10:41:48.000Z", "referer" : "-", "@version" : "1", "path" : "/opt/logs/access.log", "upstreamhost" : "-" }, "sort" : [ "yTqdNHgBXcRYjwgstiZS" ] } ] } }
第三步:取出最后一笔数据的sort值,传到search_after进行查询
GET test_json/_search { "query": { "bool": { "filter": [ { "term": { "status": "309" } } ] } }, "size": 2, "from": 0, "search_after": [ "yjqdNHgBXcRYjwgstiZS" ], "sort": [ { "_id": { "order": "desc" } } ] }
结果如下:
{ "took" : 3, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 181, "relation" : "eq" }, "max_score" : null, "hits" : [ { "_index" : "test_json", "_type" : "_doc", "_id" : "yTqdNHgBXcRYjwgstiZS", "_score" : null, "_source" : { "size" : 0, "clientip" : "127.0.0.1", "responsetime" : 0.0, "domain" : "localhost", "host" : "127.0.0.1", "status" : "309", "upstreamtime" : "-", "url" : "/index.html", "xff" : "-", "http_host" : "localhost", "@timestamp" : "2019-10-12T10:41:48.000Z", "referer" : "-", "@version" : "1", "path" : "/opt/logs/access.log", "upstreamhost" : "-" }, "sort" : [ "yTqdNHgBXcRYjwgstiZS" ] }, { "_index" : "test_json", "_type" : "_doc", "_id" : "yDqdNHgBXcRYjwgstiZS", "_score" : null, "_source" : { "size" : 0, "clientip" : "127.0.0.1", "responsetime" : 0.0, "domain" : "localhost", "host" : "127.0.0.1", "status" : "309", "upstreamtime" : "-", "url" : "/index.html", "xff" : "-", "http_host" : "localhost", "@timestamp" : "2019-10-12T10:41:48.000Z", "referer" : "-", "@version" : "1", "path" : "/opt/logs/access.log", "upstreamhost" : "-" }, "sort" : [ "yDqdNHgBXcRYjwgstiZS" ] } ] } }
3.2 基本原理
- search after 在排序的基础上,基于上一笔的sort值,查询排在它之后的数据,以此来实现分页
- search after 是无状态的,它总是查询ES索引最新的数据,这一点跟 scroll 查询完全相反
3.3 存在的问题
- sort 排序组合必须是唯一的,否则会出现数据丢失的情况。例如上面的例子,[2,“lisi”] 这个组合有2笔数据,但是第二页直接从[3,“wangwu”]开始了。建议是加上id字段作为排序字段。
- 总结
- From+Size 适合浅分页
- Scroll 适合深分页,并且数据实时要求不高,最适合离线场景
- Search After 适合深分页
————————————————
版权声明:本文为CSDN博主「FlashHobby」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_28834355/article/details/109143795