理解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等等。


kennywu76
https://elasticsearch.cn/question/2935

方法比较

与常规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
2
3
4
5
6
7
8
9
GET trans_0x0/_search?scroll=1m&pretty=true
{
"query": {
"match": {
"dip.keyword": "202.75.106.45"
}
}
, "size": 20
}

在上述的例子中,我们在_search接口后添加参数scroll并设置其为1分钟。代表在1分钟内我们认为数据不发生改动,即索引维持的时间。如果需要断点下载,在真实网络环境中情况复杂,网速并没有那么好,那么我们可以设置得长一点。

然后请求体中,我们查询dip.keyword符合”202.75.106.45”这个IP的结果。

设置size为20表示每次查询的结果,获取的、显示的结果为20条文档。