Elasticsearch滚动查询

25

我对Elasticsearch的滚动功能有点困惑。在Elasticsearch中,每当用户滚动结果集时,是否可以每次调用搜索API?根据文档

"search_type" => "scan",    // use search_type=scan
"scroll" => "30s",          // how long between scroll requests. should be small!
"size" => 50,               // how many results *per shard* you want back

这是否意味着它会每30秒执行一次搜索,并返回所有结果集,直到没有记录为止?

例如,我的ES返回总共500条记录。我从ES获取的数据是两个记录集,每个记录集都有250条记录。有没有办法我可以先显示第一个记录集的250条记录,当用户滚动时再显示第二个记录集的250条记录。请建议。

6个回答

48

你需要的是分页功能。

您可以通过查询一定大小并设置from参数来实现您的目标。由于您希望将显示设置为每批250个结果,因此可以设置size = 250,并在每个连续的查询中通过250增加from的值。

GET /_search?size=250                     ---- return first 250 results
GET /_search?size=250&from=250            ---- next 250 results 
GET /_search?size=250&from=500            ---- next 250 results
相反,扫描和滚动允许您通过单个搜索检索大量结果,理想情况下适用于重新将数据重新索引到新索引的操作。不建议将其用于实时显示搜索结果。
简要解释一下扫描和滚动,它的基本作用是扫描使用扫描请求提供的查询的索引,并返回一个scroll_id。这个scroll_id可以传递给下一个滚动请求以返回下一批结果。
考虑以下例子-
    # Initialize the scroll
    page = es.search(
      index = 'yourIndex',
      doc_type = 'yourType',
      scroll = '2m',
      search_type = 'scan',
      size = 1000,
      body = {
        # Your query's body
        }
    )
    sid = page['_scroll_id']
    scroll_size = page['hits']['total']
      
    # Start scrolling
    while (scroll_size > 0):
      print "Scrolling..."
      page = es.scroll(scroll_id = sid, scroll = '2m')
      # Update the scroll ID
      sid = page['_scroll_id']
      # Get the number of results that we returned in the last scroll
      scroll_size = len(page['hits']['hits'])
      print "scroll size: " + str(scroll_size)
      # Do something with the obtained page

在上面的示例中,发生了以下事件 -

  • 滚动条被初始化。这将返回第一批结果以及scroll_id。
  • 对于每个后续的滚动请求,会发送更新后的scroll_id(在上一个滚动请求中收到),并返回下一批结果。
  • 滚动时间基本上是保持搜索上下文活动的时间。如果在设置的时间范围内没有发送下一个滚动请求,则搜索上下文将丢失,并且结果将不会返回。这就是为什么它不应该用于具有大量文档索引的实时结果显示。

4
scroll='2m'是什么意思?它代表2分钟吗?它有什么用途? - Amogh Mishra
4
@AmoghMishra 是的,它意味着2分钟。 - omurbek
6
“@AmoghMishra scroll”会对查询结果进行快照,然后将其存储在内存中。这意味着如果您添加/更新记录,后续的滚动操作将无法看到它们。 - maembe
1
"search_type=scan" 已被弃用,并在 v5.0 中移除。您不需要它。 - Harry Wood
你希望每次SID都不同吗?我每次得到的SID都是相同的。可能出了什么问题? - Nguai al
滚动参数(传递给搜索请求和每个滚动请求)告诉Elasticsearch应该保持搜索上下文的存活时间。它的值(例如1m,参见时间单位)不需要足够长以处理所有数据 - 它只需要足够长以处理先前的结果批次。每个滚动请求(带有滚动参数)设置一个新的到期时间。如果滚动请求没有传递滚动参数,则搜索上下文将作为该滚动请求的一部分被释放。 - taichi_tiger

16

你对 scroll 属性的作用误解了。它并不表示 elasticsearch 将在 30 秒后获取下一页的数据。当你进行第一次滚动请求时,你需要指定何时关闭滚动上下文。 scroll 参数告诉 elasticsearch 在 30 秒后自动关闭滚动上下文。

在第一次滚动请求后,你将在响应中收到 scroll_id 参数。对于下一页,你需要传递该值以获取滚动响应的下一页。如果你在 30 秒内没有进行下一次滚动请求,滚动请求将被关闭,你将无法获取那个滚动请求的下一页。


当新的scroll_id和context生成时,前面的scroll_id及其上下文是否会自动清除?还是所有的scroll_id及其上下文都要保持活动状态直到指定的时间过期或所有数据已经滚动完成? - Harshit Nagar
1
ids将保持活动状态直到指定时间结束,您可以拥有多个滚动上下文,每个上下文都有其生命周期。 - Ruben Vardanyan

14
您所描述的一个使用案例实际上是搜索结果分页,对于任何搜索查询都可用,并受到10k结果的限制。scroll请求是在需要超过10k限制时使用的,在scroll查询中,您甚至可以获取整个文档集合。
可能混淆的源头在于scroll术语是有歧义的:它是一种查询类型,也是这种查询的一个参数的名称(如其他评论中提到的,这是ES将等待您获取下一个滚动块的时间)。 scroll查询很重,应该避免使用,直到绝对必要。事实上,在文档中说:

滚动不是为实时用户请求而设计的,而是为处理大量数据而设计的...

现在关于您的另一个问题:

在elasticsearch中,是否可以在用户滚动结果集时每次调用搜索API?

是的,甚至可以进行几个并行滚动请求

每个滚动都是独立的,并且可以像任何滚动请求一样并行处理。


3
Elasticsearch滚动API文档中也解释了这种行为。
结果大小默认为10k,在运行时可以根据需要进行覆盖。
PUT { "index" : { "max_result_window" : 500000} }

滚动id的生存时间在每个滚动请求中使用参数"scroll"来定义,例如:
..
  "scroll" : "5m"
  ..

1
在最近的Elasticsearch版本中,您将使用search_after。您在那里设置的keep_alive(与滚动中的timeout类似)仅是处理一页所需的时间。
这是因为Elasticsearch将在该时间内保持您的“搜索上下文”处于活动状态,然后将其删除。此外,Elasticsearch不会自动为您获取下一页,您需要通过发送具有上一个请求的ID的请求来实现。

0

在elasticsearch中,一次最多只能获取10K数据,因此使用滚动API是明智的选择。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接