理解scroll search
理解Scroll Search
概念
ES的搜索是分2个阶段进行的,即Query阶段和Fetch阶段。 Query阶段比较轻量级,通过查询倒排索引,获取满足查询结果的文档ID列表。 而Fetch阶段比较重,需要将每个shard的结果取回,在协调结点进行全局排序。 通过From+size这种方式分批获取数据的时候,随着from加大,需要全局排序并丢弃的结果数量随之上升,性能越来越差。
而Scroll查询,先做轻量级的Query阶段以后,免去了繁重的全局排序过程。 它只是将查询结果集,也就是doc id列表保留在一个上下文里, 之后每次分批取回的时候,只需根据设置的size,在每个shard内部按照一定顺序(默认doc_id续), 取回这个size数量的文档即可。
由此也可以看出scroll不适合支持那种实时的和用户交互的前端分页工作,其主要用途用于从ES集群分批拉取大量结果集的情况,一般都是offline的应用场景。 比如需要将非常大的结果集拉取出来,存放到其他系统处理,或者需要做大索引的reindex等等。
方法比较
与常规search相比
首先,我们要记住ES的搜索是分两步进行的,第一步相当于更具倒排索引找对应数据的ID,第二步是从各个分片中取回ID对应的数据。
第一个阶段较为轻量化,因为是只是在倒排索引里找。第二个阶段比较重量,因为其不仅需要到各个分片中取回数据,还需要在进行全局排序(因为从各个分片中取回的数据可能是散乱的),因为我们需要找到在查询的时间内变化的结果,如果变化则丢弃。
而滚动查询(scroll search)则面去了全局排序的过程,fetch到结果后,直接保存在查询结果集,到设置到的size后直接取回,此时并不考虑已经取回的数据是否变化了。
在数据量非常大的情况下,size也相对较小的话,会产生一种滚动显示的效果,但要记住滚动并不是为了实时的用户响应,而是为了处理大量的数据。并且scroll也很难
与Scan相比
相比于常规的search,scroll search虽说在不进行全局排序的,但在每个size内进行搜索得到结果时也是会进行排序的。如果我们不考虑排序,只想要找有对应的数据,那么可以用scan。scan模式不进行全局排序,也不进行“分步”排序。
为什么要排序?
为什么常规的search和scroll search都要进行排序呢?因为在真实环境中我们有很多复杂的需求,不是每次查询都能跑一遍全部的量的
例如,企业级日志的数量每天都有成千上万条,如果我们需要在一个月内的日志数据(分布式存储)中,找到某一个时间段的全部请求IP,如果不排序,我们就无法定位到一个具体的时间段。因为分布式存储时,每个数据都在一个切片中,在搜索时,需要对每个切片进行一下排序,才能知道,第XXX条就是我们要查的开始文档,每个切片都要排序,然后在常规search后又要进行进行一次全局排序来汇总。
如果此时使用scan方式,那么相当于我们在每个切片中都进行着内容匹配,不作任何排序,从头到尾地进行着比对。这个是不现实的,也是不符合需求的。
此时,我们就可以使用scroll search,为什么呢?理由有4点:
- 数据量很大,scroll search减少了全局排序的时间
- 数据是冷的,过往时间的日志数据不会变动
- 我们的目的是找数据,不是有边查边改动或者其他复杂的需求
- 我们要设置在一定的范围,需要在查询时进行过滤设置
适用场景
- 最好是冷数据,或者数据变动不是非常频繁
- 数据量很大,我们需要减少时间
- 目的是拉取结果集
例子
1 | GET trans_0x0/_search?scroll=1m&pretty=true |
在上述的例子中,我们在_search
接口后添加参数scroll
并设置其为1分钟。代表在1分钟内我们认为数据不发生改动,即索引维持的时间。如果需要断点下载,在真实网络环境中情况复杂,网速并没有那么好,那么我们可以设置得长一点。
然后请求体中,我们查询dip.keyword符合”202.75.106.45”这个IP的结果。
设置size为20表示每次查询的结果,获取的、显示的结果为20条文档。