当前位置:
首页
文章
后端
详情

如何解决Elasticsearch的深度翻页问题

使用ES做搜索引擎拉取数据的时候,如果数据量太大,通过传统的from + size的方式并不能获取所有的数据(默认最大记录数10000),因为随着页数的增加,会消耗大量的内存,导致ES集群不稳定。

ES提供了3中解决深度翻页的操作,分别是scroll、sliced scroll 和 search after:

scroll

scroll api提供了一个全局深度翻页的操作, 首次请求会返回一个scroll_id,使用该scroll_id可以顺序获取下一批次的数据;scroll 请求不能用来做用户端的实时请求,只能用来做线下大量数据的翻页处理,例如数据的导出、迁移和_reindex操作,还有同一个scroll_id无法并行处理数据,所以处理完全部的数据执行时间会稍长一些。

  • 例如我们使用scroll翻页获取包含elasticsearch的Twitter,那么首次请求的语句如下:
POST /twitter/_search?scroll=1m
{
    "size": 100,
    "query": {
        "match" : {
            "title" : "elasticsearch"
        }
    }
}

其中scroll=1m是指scroll_id保留上下文的时间

  • 首次请求会返回一个scroll_id,我们根据这个值去不断拉取下一页直至没有结果返回:
POST /_search/scroll 
{
    "scroll" : "1m", 
    "scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ==" 
}

针对scroll api下,同一个scroll_id无法并行处理数据的问题,es又推出了sliced scroll,与scroll api的区别是sliced scroll可以通过切片的方式指定多scroll并行处理。

sliced scroll

sliced scroll api 除指定上下文保留时间外,还需要指定最大切片和当前切片,最大切片数据一般和shard数一致或者小于shard数,每个切片的scroll操作和scroll api的操作是一致的:

GET /twitter/_search?scroll=1m
{
    "slice": {
        "id": 0, 
        "max": 2 
    },
    "query": {
        "match" : {
            "title" : "elasticsearch"
        }
    }
}
GET /twitter/_search?scroll=1m
{
    "slice": {
        "id": 1,
        "max": 2
    },
    "query": {
        "match" : {
            "title" : "elasticsearch"
        }
    }
}

因为支持并行处理,执行时间要比scroll快很多。

search after

上面两种翻页的方式都无法支撑用户在线高并发操作,search_after提供了一种动态指针的方案,即基于上一页排序值检索下一页实现动态分页:

  • 首次查询
GET twitter/_search
{
    "size": 10,
    "query": {
        "match" : {
            "title" : "elasticsearch"
        }
    },
    "sort": [
        {"date": "asc"},
        {"tie_breaker_id": "asc"}      
    ]
}

因为是动态指针,所以不需要像scroll api那样指定上下文保留时间了

  • 通过上一页返回的date + tie_breaker_id最后一个值做为这一页的search_after:
GET twitter/_search
{
    "size": 10,
    "query": {
        "match" : {
            "title" : "elasticsearch"
        }
    },
    "search_after": [1463538857, "654323"],
    "sort": [
        {"_score": "desc"},
        {"tie_breaker_id": "asc"}
    ]
}

说白了 search_after 并没有解决随机跳页查询的场景,但是可以支撑多query并发请求;search_after 操作需要指定一个支持排序且值唯一的字段用来做下一页拉取的指针,这种翻页方式也可以通过bool查询的range filter实现。

免责申明:本站发布的内容(图片、视频和文字)以转载和分享为主,文章观点不代表本站立场,如涉及侵权请联系站长邮箱:xbc-online@qq.com进行反馈,一经查实,将立刻删除涉嫌侵权内容。

同类热门文章

深入了解C++中的new操作符:使用具体实例学习

C++中的new操作符是动态分配内存的主要手段之一。在程序运行时,我们可能需要动态地创建和销毁对象,而new就是为此提供了便利。但是,使用new也常常会引发一些问题,如内存泄漏、空指针等等。因此,本文将通过具体的示例,深入介绍C++中的new操作符,帮助读者更好地掌握其使用。


深入了解C++中的new操作符:使用具体实例学习

怎么用Java反射获取包下所有类? 详细代码实例操作

Java的反射机制就是在运行状态下,对于任何一个类,它能知道这个类的所有属性和方法;对于任何一个对象,都能调用这个对象的任意一个方法。本篇文章将通过具体的代码示例,展示如何通过Java反射来获取包下的所有类。


怎么用Java反射获取包下所有类? 详细代码实例操作

员工线上学习考试系统

有点播,直播,在线支付,三级分销等功能,可以对学员学习情况的监督监控,有源码,可二次开发。支持外网和局域网私有化部署,经过测试源码完整可用!1、视频点播:视频播放,图文资料,课件下载,章节试学,限时免

员工线上学习考试系统

了解Java中的volati关键字的作用 以及具体使用方法

本篇文章将和大家分享一下Java当中的volatile关键字,下面将为各位小伙伴讲述volatile关键字的作用以及它的具体使用方法。


了解Java中的volati关键字的作用 以及具体使用方法

Java Map 所有的值转为String类型

可以使用 Java 8 中的 Map.replaceAll() 方法将所有的值转为 String 类型: 上面的代码会将 map 中所有的值都转为 String 类型。 HashMap 是 Java

Java Map 所有的值转为String类型