浅析Elasticsearch大数据下深度分页问题

Posted 中兴大数据

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅析Elasticsearch大数据下深度分页问题相关的知识,希望对你有一定的参考价值。

文 | 程丽华

Elasticsearch是一款非常优秀的实时分布式搜索分析引擎,基于它能够达到实时搜索、稳定、可靠、快速、安装方便等优点,目前已经被广泛使用。在使用过程中不可回避的会遇到大数据的遍历、深度分页等问题,本文基于Easticsearch官网和自己的实践测试经验来小结下Elasticsearch深度分页问题。

深度分页存在的问题

深度分页问题之所以存在,是和Elasticsearch搜索内部执行原理分不开的。

如果你想查询第5000-5100数据,查询官网API你很容易就知道,发送如下查询条件就可以做到:

POST auditlog_operation/operlog/_search

    {

        “from”:5000   //from:定义从哪里开始拿数据

        “size”:100    //size:定义一共拿多少条数据

    }

查询流程如下:

  1. 客户端发送请求到某个node节点。

  2. 此node将请求广播到各分片,各分片各自查询前5100条数据。

  3. 查询结果返回给node节点,node对结果进行合并整合,取出前5100条数据。

  4. 返回给客户端。

相信就算是技术小白也能看出上述深度分页查询的问题,如果你要深度获取1000000到1000100页的数据,性能问题会非常明显的暴露出来:CPU、内存、IO、网络带宽等等,而且Elasticsearch本身就是个Java应用,若并发上去,Elasticsearch会快就会OOM。

解决思路

查询请求:

POST auditlog_operation/operlog/_search

    {

        “from”:10000

        “size”:100

    }

如果你尝试发送上述from+size请求来获取10000-10100条数据,对不起会返回错误:

 {"error":{"root_cause":[{"type":"query_phase_execution_exception","reason":"Resultwindow is too large, from + size must be less than or equal to: [1000000] butwas [1000100]. See the scroll api for a more efficient way to request largedata sets. This limit can be set by changing the [index.max_result_window]index levelparameter."}],"type":"search_phase_execution_exception","reason":"allshards failed","phase":"query_fetch","grouped":true,"failed_shards":[{"shard":0,"index":"auditlog_operation","node":"iqu-KVKjTRmT3YcT9XAu_w","reason":{"type":"query_phase_execution_exception","reason":"Resultwindow is too large, from + size must be less than or equal to: [1000000] butwas [1000100]. See the scroll api for a more efficient way to request largedata sets. This limit can be set by changing the [index.max_result_window]index level parameter."}}]},"status":500}

迅速查询官网得到更明确的提示:

浅析Elasticsearch大数据下深度分页问题

翻译成中文为:注意 from+size不再适用于查询数据超过index.max_result_window设置值,此默认值为10000。查看 Scroll 或 Search After来获取更高效的深层分页(滚动)。

由此可以得到两个结论:

  1. 你可以修改index.max_result_window设置值来继续使用from+size做分页查询。当然效率肯定不高。

  2. 如果要找更高效的深度分页方式,请使用Scroll  或者Search After。

Scroll API

Scroll API更适用于检索大量数据(甚至全部数据)。它先做一个初始阶段搜索然后持续批量从Elasticsearch里拉取结果直到返回结果为空。这有点像传统数据库里的cursors(游标)。

  • Scroll API

   Scroll分两步来完成整个遍历过程:

1、初始化

POST   index/type/_search?scroll=1m

    {
        "query": { "match_all": {}}
    }

参数解析:

  • 和普通查询一样,可以指定index、type、查询条件等。

  • Scroll:初始化请求必须指定Scroll参数,此参数告诉Elasticsearch 他要保存此次搜索的上下文多长时间。

2、遍历

POST /_search?scroll=1m
    {
        "scroll_id":"XXXXXXXXXXXXXXXXXXXXXXX I am scroll id XXXXXXXXXXXXXXX"
    }

参数解析:

  • scroll_id:初始化或上次遍历的返回的scroll_id。

  • Scroll:必须指定上下文搜索的保持时间,超时scroll_id就过期不能再使用。但是设置时间不可过长,只要能让其保持到下一次遍历(两次遍历时间)完成即可。

  • index、type不用指定。

  • 默认每次取10条。若需要修改,添加size参数,size的设置也要考虑性能问题,过大一次取数据过多不是自己应用OOM就是es服务OOM。

  • 重复此请求直到返回数据为空,遍历结束。

  • 清除scroll_id

Scroll为了保证遍历不会因为超时而失败,开发人员可能会把超时时间设置稍长,或者遍历被人为中途停止,这个时候可能需要调用清除scroll_id接口。

DELETE    /_search/scroll

    {  

        "scroll_id" : ["c2NhbjsxOzY0OmRVRUN4TG5TUXYyaXRIT0Q5SUxiR0E7MTt0b3RhbF9oaXRzOjIwNjgxMjg7"]  

    }

DELETE   /_search/scroll/_all

参数解析:

  • scroll_id数组:传入要删除的id数组。

  • 若全部清除,可直接传入all。

  • 实际分页应用场景

Scroll API只能遍历全部数据,顶多做到向后翻页,不能向前翻页或者直接跳转到某一页。那在实际使用大数据量场景中,需要实现向前向后翻、直接跳转到某页等功能。就目前我已知的Elasticsearch查询,无法做到真正意义的分页实际应用。我们经过测试和分析,打算结合Scroll API和from+size,融合两者的特点来实现真正意义上的分页查询。

举例:数据库有5649条数据,id依次从1到5649。

1、先使用Scroll API进行遍历全部数据(结果按照id排序)。

2、依次遍历,每次取1000条数据(取多少根据内存考虑),缓存起始id。

上例缓存的id数组为:【1,1001,2001,3001,4001,5001】

3、分页查询时依然使用from+size,只是会根据上述取到的id数据先进行一次过滤,再在1000数据内使用from+size来处理。

例如按照每页100条数据,用户想直接查看第32页的数据的话,那就是发送请求以下请求:

POSTauditlog_operation/operlog/_search

    {

        “from”:2,

        “size”:100,   //这1000里取第二页的100条

        "query": {

            "bool":{

                "must":[{

                    "range":{

                        "id":{

                            "gte":"3001",

                            "lt":"4001"   //先将此范围限制在3001-4000条之间

                        }

                    }

                }],

                "must_not":[],

                "should":[]

            }

        },

    }

我们在实际开发中使用的Elasticsearch提供的API。代码找对应的API使用就可以,没发现特殊需要注意的坑,此文不再附上。

总结

  • 若有需要查询大量或全部数据却并不关心顺序的应用场景,建议使用scroll-scan,从性能上应该会提高不少。

  • 本文所使用的Elasticsearch版本为2.4.1。

以上是关于浅析Elasticsearch大数据下深度分页问题的主要内容,如果未能解决你的问题,请参考以下文章

ElasticSearch深度分页详解

ElasticSearch 分页问题分析

干货 | 全方位深度解读 Elasticsearch 分页查询

京东面试题:ElasticSearch深度分页解决方案

Elasticsearch:运用search_after来进行深度分页

京东面试题:ElasticSearch深度分页解决方案