ES的深度分页解决方案

索引:共4T,5个索引,共100亿条数据

查询语句:

{
   "query":{
       "term":{
           "app_servername":"set-app-heatontime01"
       }
   },
   "size":10000,
   "sort": [
       {"es_timestamp": "asc"},
   ]
}

符合条件结果总共5亿条数据。

scroll测试

拉取结果耗时:









拉取条数

10万

20万

50万

100万

200万

300万

500万

耗时

13.5s

30s

76s

158s

313s

560s

787s

es的并发scroll不适合深度翻页,只适合拉取所有数据。

es search_after也不适合做深度分页,分页多了,内存不够,将查询失败。

我们在分页的时候如果用from+size的话,from + size 默认不能超过1万条数据。

使用from + size方式是将请求达到分片节点上,如果有n个副分片,则查询数据是 n * (from+size) 如果from很大的话,会造成oom或者网络资源的浪费。

若使用scroll的话,尽管能读取许多数据,但是查询出来的结果都是无序的。

对于深度分页,到底有没有比较理想的解决方案,既能拉取比较多的数据,拉取的数据也都是有序的?那么你可以了解下search_after。

第一步

代码块

GET twitter/tweet/_search
{
    "size": 10,
    "query": {
        "match" : {
            "title" : "elasticsearch"
        }
    },
    "sort": [
        {"es_timestamp": "asc"},
        {"_uid": "desc"}
    ]
}

和我们正常查询没有什么区别,这里必须要使用sort进行排序。

同时sort中必须至少包含一个唯一的字段来进行排序,推荐使用_uid(必须有)。

同时日志中心的数据,也尽量将es_timestamp加上去一起排序。

若这里没有唯一的字段,那么每次获取结果将不够精确,影响使用。

返回的response如下:

代码块

  {
            "_index": "log.xxx.20181120_2",
            "_type": "logs",
            "_id": "AWcvRPOwqf9vJFGaVemX",
            "_score": null,
            "_source": {
               "mt_level": "WARN",
               "traceId__": "5919513527137007410",
               "mt_appkey": "xxxx",
               "mt_thread": "xxxx0",
               "es_timestamp": "2018/11/20 11:58:23 +0800",
               "mt_logger_name": "xxxx",
               "mt_datetime": "2018-11-20 11:58:23+0800",
               "message": " select scope cost:0\n",
               "mt_servername": "xxxxx"
            },
            "sort": [
               1542686303000,
               "logs#AWcvRPOwqf9vJFGaVemX"
            ]
         }

注意这里返回的sort结构。返回了每条数据的es_timestamp和_uid。

第二次分页

代码块

GET twitter/tweet/_search
{
    "size": 10,
    "query": {
        "match" : {
            "title" : "elasticsearch"
        }
    },
    "search_after": [1463538857, "tweet#654323"],
    "sort": [
        {"es_timestamp": "asc"},
        {"_uid": "desc"}
    ]
}

若我们想接着上次读取的结果进行读取下一页数据,第二次查询在第一次查询时的语句基础上添加search_after,并指明从哪个数据后开始读取。

search_after原理比较简单:

因为我们在sort中指明了唯一字段_uid,所以查询的数据整体肯定是有序的,在第二次查询时,同时将search_after指定的值作为查询条件(类似游标),指定从整个有序数据哪个位置继续查询。

缺陷:

search_after并不能代替from+ size和scroll,它每第二次读取时,必须要指定查询地址(游标search_after),实际使用时,只能一页一页的向下翻,而不能跳页查询。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值