在Elasticsearch中,我们可以通过size和from来对我们的结果来进行分页。但是对于数据量很大的索引,这是有效的吗?Scroll API可用于从单个搜索请求中检索大量结果(甚至所有结果),这与在传统数据库上使用cursor的方式非常相似。Scroll不是用于实时用户请求,而是用于处理大量数据,例如,用于处理大量数据。 为了将一个索引的内容重新索引到具有不同配置的新索引中。

为了说明问题,我们今天先创建一个叫做twitter的Index:

    POST _bulk
{ "index" : { "_index" : "twitter", "_id": 1} }
{"user":"双榆树-张三","message":"今儿天气不错啊,出去转转去","uid":2,"age":20,"city":"北京","province":"北京","country":"中国","address":"中国北京市海淀区","location":{"lat":"39.970718","lon":"116.325747"}}
{ "index" : { "_index" : "twitter", "_id": 2 }}
{"user":"东城区-老刘","message":"出发,下一站云南!","uid":3,"age":30,"city":"北京","province":"北京","country":"中国","address":"中国北京市东城区台基厂三条3号","location":{"lat":"39.904313","lon":"116.412754"}}
{ "index" : { "_index" : "twitter", "_id": 3} }
{"user":"东城区-李四","message":"happy birthday!","uid":4,"age":30,"city":"北京","province":"北京","country":"中国","address":"中国北京市东城区","location":{"lat":"39.893801","lon":"116.408986"}}
{ "index" : { "_index" : "twitter", "_id": 4} }
{"user":"朝阳区-老贾","message":"123,gogogo","uid":5,"age":35,"city":"北京","province":"北京","country":"中国","address":"中国北京市朝阳区建国门","location":{"lat":"39.718256","lon":"116.367910"}}
{ "index" : { "_index" : "twitter", "_id": 5} }
{"user":"朝阳区-老王","message":"Happy BirthDay My Friend!","uid":6,"age":50,"city":"北京","province":"北京","country":"中国","address":"中国北京市朝阳区国贸","location":{"lat":"39.918256","lon":"116.467910"}}
{ "index" : { "_index" : "twitter", "_id": 6} }
{"user":"虹桥-老吴","message":"好友来了都今天我生日,好友来了,什么 birthday happy 就成!","uid":7,"age":90,"city":"上海","province":"上海","country":"中国","address":"中国上海市闵行区","location":{"lat":"31.175927","lon":"121.383328"}}

在上面,我们创建了6个文档。这些文档的数量虽然不是很多,但是我们想为了说明问题的方便。在实际的使用中,我们可能有成百上千的文档。

下面,我们通过size和from的方法来进行分页。假如我们把sizs设置为2,那么,我们可以通过如下写的方法来进行分页。

    GET twitter/_search?size=2&from=0
GET twitter/_search?size=2&from=2
GET twitter/_search?size=2&from=4

这样,我们每次可以得到2个文档,从而对我们的Index进行分页。我们可以得到这些数据并在自己的页面上或应用里进行展示。通常这样的每个请求返回的上线是10K。如果超过这个上限的话,这样的方法将不再适合。

上面的这种方法,对于小量的数据是可行的,但是对于大量的数据,而且我们需要进行sort时,这个有可能变得力不从心,比如:

    GET twitter/_search
{
"query": {
"match": {
"city": "北京"
}
},
"from": 2,
"size": 2,
"sort": [
{
"user.keyword": {
"order": "desc"
}
}
]
}

你可以想象当你更深入地进行分页时,它会变得多么低效。 例如,如果更改mapping并希望将所有现有数据重新索引到新索引中,您可能没有足够的内存来对所有结果进行排序以返回最后一页的数据。

对于这种应用场景,你可以使用scan搜索类型。我们可以这么做:

1. 使用scroll来返回一个初始的搜索,并返回一个scroll ID

    GET twitter/_search?scroll=1m
{
"query": {
"match": {
"city": "北京"
}
},
"size": 2
}

这里的scroll=1m,表明Elasticsearch允许等待的时间是1分钟。如果在一分钟之内,接下来的scroll请求没有到达的话,那么当前的请求的上下文将会丢失。

返回的结果是:

    {
"_scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAFh8WWUdCVlRMUllRb3UzMkdqb0IxVnZNUQ==",
"took" : 31,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : 0.48232412,
"hits" : [
{
"_index" : "twitter",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.48232412,
"_source" : {
"user" : "双榆树-张三",
"message" : "今儿天气不错啊,出去转转去",
"uid" : 2,
"age" : 20,
"city" : "北京",
"province" : "北京",
"country" : "中国",
"address" : "中国北京市海淀区",
"location" : {
"lat" : "39.970718",
"lon" : "116.325747"
}
}
},
{
"_index" : "twitter",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.48232412,
"_source" : {
"user" : "东城区-老刘",
"message" : "出发,下一站云南!",
"uid" : 3,
"age" : 30,
"city" : "北京",
"province" : "北京",
"country" : "中国",
"address" : "中国北京市东城区台基厂三条3号",
"location" : {
"lat" : "39.904313",
"lon" : "116.412754"
}
}
}
]
}
}

在这里,我们可以看到一个返回的_scroll_id。这个_scroll_id将会被用于接下来的请求。

2. 使用_scroll_id,再次请求

利用上次请求返回来的_scroll_id,再次请求以获得下一个page的信息:

    GET _search/scroll
{
"scroll": "1m",
"scroll_id":"DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAHC8WWUdCVlRMUllRb3UzMkdqb0IxVnZNUQ=="
}

在这里必须指出的是:

  • 这里填写的scroll_id是上一个请求返回的值
  • 这个scroll_id的有效期是我们在第一次搜索时定义的1m,也就是1分钟。如果超过了,这个就没有用

运行后返回的结果是:

    {
"_scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAHS0WWUdCVlRMUllRb3UzMkdqb0IxVnZNUQ==",
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : 0.48232412,
"hits" : [
{
"_index" : "twitter",
"_type" : "_doc",
"_id" : "3",
"_score" : 0.48232412,
"_source" : {
"user" : "东城区-李四",
"message" : "happy birthday!",
"uid" : 4,
"age" : 30,
"city" : "北京",
"province" : "北京",
"country" : "中国",
"address" : "中国北京市东城区",
"location" : {
"lat" : "39.893801",
"lon" : "116.408986"
}
}
},
{
"_index" : "twitter",
"_type" : "_doc",
"_id" : "4",
"_score" : 0.48232412,
"_source" : {
"user" : "朝阳区-老贾",
"message" : "123,gogogo",
"uid" : 5,
"age" : 35,
"city" : "北京",
"province" : "北京",
"country" : "中国",
"address" : "中国北京市朝阳区建国门",
"location" : {
"lat" : "39.718256",
"lon" : "116.367910"
}
}
}
]
}
}

显然这次返回的是2个文档。我们需要再次使用同样的办法来得到最后一个page的结果:

    {
"_scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAADeoWeno1UkF2RWZRd202VW1HQXRlOWFUdw==",
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : 0.48232412,
"hits" : [
{
"_index" : "twitter",
"_type" : "_doc",
"_id" : "5",
"_score" : 0.48232412,
"_source" : {
"user" : "朝阳区-老王",
"message" : "Happy BirthDay My Friend!",
"uid" : 6,
"age" : 50,
"city" : "北京",
"province" : "北京",
"country" : "中国",
"address" : "中国北京市朝阳区国贸",
"location" : {
"lat" : "39.918256",
"lon" : "116.467910"
}
}
}
]
}
}

显然,这次返回的结果只有一个数值,比我们请求的page大小2要小。如果我们利用返回的_scroll_id再次请求时,我们可以看返回的结果是:

    {
"_scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAADeoWeno1UkF2RWZRd202VW1HQXRlOWFUdw==",
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : 0.48232412,
"hits" : [ ]
}
}

这次是一个结果都没有。

如果完成此过程,则需要清理上下文,因为上下文在超时之前仍会占用计算资源。 如下面的屏幕快照所示,您可以使用scroll_id参数在DELETE API中指定一个或多个上下文:

    DELTE_search/scroll
{
"scroll_id":"DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAHC8WWUdCVlRMUllRb3UzMkdqb0IxVnZNUQ=="
}

参考:
【1】Elasticsearch Scroll
【2】https://www.elastic.co/guide/en/elasticsearch/reference/7.4/search-request-body.html#request-body-search-scroll

Elasticsearch:运用scroll接口对大量数据实现更好的分页的更多相关文章

  1. Elasticsearch利用scroll查询获取所有数据

    Elasticsearch有两种分页方式,一种是通过from和size条件来实现,但是该方法开销比较大,另一种是利用scroll来实现,通过scroll来实现分页获取所有的数据,下面是利用python ...

  2. Elasticsearch Sliced Scroll分页检索案例分享

    面试:你懂什么是分布式系统吗?Redis分布式锁都不会?>>>   The best elasticsearch highlevel java rest api-----bboss ...

  3. 防抖与节流 & 若每个请求必须发送,如何平滑地获取最后一个接口返回的数据

    博客地址:https://ainyi.com/79 日常浏览网页中,在进行窗口的 resize.scroll 或者重复点击某按钮发送请求,此时事件处理函数或者接口调用的频率若无限制,则会加重浏览器的负 ...

  4. elasticsearch 深入 —— Scroll滚动查询

    Scroll search 请求返回一个单一的结果"页",而 scroll API 可以被用来检索大量的结果(甚至所有的结果),就像在传统数据库中使用的游标 cursor. 滚动并 ...

  5. elasticsearch REST API方式批量插入数据

    elasticsearch REST API方式批量插入数据 1:ES的服务地址  http://127.0.0.1:9600/_bulk 2:请求的数据体,注意数据的最后一行记得加换行 { &quo ...

  6. [搜索]ElasticSearch Java Api(一) -添加数据创建索引

    转载:http://blog.csdn.net/napoay/article/details/51707023 ElasticSearch JAVA API官网文档:https://www.elast ...

  7. 简述在ADO中使用接口的抽象数据提供程序以及ADO.NET数据提供程序工厂模型

    如何在ADO中使用接口的抽象数据提供程序 在cofig中 appSettings下,配置数据连接类型 <appSettings> <!--这个键值映射到枚举值中的某个值--> ...

  8. vue 配合vue-resource调用接口,获取数据

    1.先用node+express+mysql简单配置一下后台 const express = require('express');const mysql = require('mysql');con ...

  9. C#调用接口返回json数据中含有双引号 或其他非法字符的解决办法

    这几天,调用别人接口返回json数据含有特殊符号(双引号),当转换成json对象总是报错, json字符格式如下 { "BOXINFO":[ { ", "ITE ...

随机推荐

  1. 最新 4399java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.4399等10家互联网公司的校招Offer,因为某些自身原因最终选择了4399.6.7月主要是做系统复习.项目复盘.Leet ...

  2. (生鲜项目)08. ModelSerializer 实现商品列表页, 使用Mixin来实现返回, 以及更加方便的ListAPIView, 以及分页的设置

    第一步: 学会使用ModelSerializer, 并且会使用ModelSerializer相互嵌套功能 1. goods.serializers.py from rest_framework imp ...

  3. Python安装pip3

    在新的电脑上,偶尔会出现无法安装pip的问题. 今天看见了一位大神的方法: 在cmd窗口中输入python -m ensurepip 然后使用pip命令安装其他包.pip3 install 模块名 说 ...

  4. vue项目富文本编辑器vue-quill-editor之自定义图片上传

    使用富文本编辑器的第一步肯定是先安装依赖 npm i vue-quill-editor 1.如果按照官网富文本编辑器中的图片上传是将图片转为base64格式的,如果需要上传图片到自己的服务器,需要修改 ...

  5. mysql中的反引号``

    [1]反引号`,数字1左边的符号.tab键上面的符号. 它是为了区分MYSQL的保留字与普通字符而引入的符号. 不加反引号建的表不能包含MYSQL保留字,否则出错 如上图,很明显的,如果我们直接建立名 ...

  6. SQL SERVER YEAR函数

    定义: YEAR函数返回指定日期的年的部分 语法: YEAR(date) 参数: ①date参数是合法的日期表达式. 返回值: int型数据 例:  声明:本文是本人查阅网上及书籍等各种资料,再加上自 ...

  7. spring-data-redis 2.0 的使用

    在使用Spring Boot2.x运行Redis时,发现百度不到顺手的文档,搞通后发现其实这个过程非常简单和简洁,觉得有必要拿出来分享一下. Spring Boot2.x 不再使用Jedis,换成了L ...

  8. 前端工程师应该知道的yarn知识

    yarn 是在工作中离不开的工具,但在工作中,很多人基本只会使用 yarn install,而且会手动删除 node-modules,或删除 yarn.lock 文件等不规范操作.本文将从一些基础的知 ...

  9. js 替换html

    function getInfo(){ var player_name=$("#name").val(); $.ajax({ url: 'get_wefare', method: ...

  10. Ocelot + Consul的demo

    参考大佬的博客写的:https://www.cnblogs.com/alan-lin/p/9126155.html:也可以参考这篇博客:https://www.cnblogs.com/axzxs200 ...