es深度分页原因概念及处理方法
概述
当使用es分页查询的时候,如果查询的数据太靠后了,就会产生深度分页问题。
假设es有3个节点,node1,node2,node3 查询 limti 50000,50 假设请求的是node1,此时会在每个节点上抓出 50050条数据,然后在node1汇总排序,取出50条数据。此时就发生了深度分页问题。es在2.0之后有个配置参数max_result_window限制了深度分页最大是10000。
search_after查询
查询的是实时的数据,但是每次查询需要带上上一次查询的最后一个sort值。并且需要文档中有一个字段保存唯一值,一般就用uuid来填充了。
所以在查询的时候需要一页一页的查询下去,因为需要拿到上一次的sort值,如果一次性查询 limit 20000,20还是不行的,需要从第一页开始查询下去。
请求demo 文档中的uid属性是唯一的
GET /student/student/_search { "query":{ "match_all": { } }, "size":2, "sort":[ { "uid": "desc" } ] }
结果demo,结果集中有sort字段,下一次的search_after查询需要带上此次最后一条记录的sort的值
{ "took" : 1, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 6, "max_score" : null, "hits" : [ { "_index" : "student", "_type" : "student", "_id" : "6", "_score" : null, "_source" : { "uid" : 1006, "name" : "dehua", "age" : 27, "class" : "3-1" }, "sort" : [ 1006 ] }, { "_index" : "student", "_type" : "student", "_id" : "5", "_score" : null, "_source" : { "uid" : 1005, "name" : "fucheng", "age" : 23, "class" : "2-3" }, "sort" : [ 1005 ] } ] } }
下一次的search_after查询
GET /student/student/_search { "query":{ "match_all": { } }, "size":2, "search_after":[1005], "sort":[ { "uid": "desc" } ] }
游标查询
适合大数据量的一次性查询 类似mysql的游标查询,在查询的时候生成一个快照,然后不断的分批从快照中获取数据,可以设置这个快照的过期时间。此时文档数据被修改是不会同步给快照中的数据的。
请求demo
GET /student/student/_search { "query":{ "match_all": { } }, "size":2, "search_after":[1005], "sort":[ { "uid": "desc" } ] }
第一次响应的数据中有_scroll_id字段,后面的scroll查询都要带上这个字段
后面的连续查询 当结果集为空的时候代表查询完毕
这个index中一共有6条数据,游标查询每次查询2条