Scroll

search 请求返回一个单一的结果“页”,而 scroll API 可以被用来检索大量的结果(甚至所有的结果),就像在传统数据库中使用的游标 cursor。

滚动并不是为了实时的用户响应,而是为了处理大量的数据,例如,为了使用不同的配置来重新索引一个 index 到另一个 index 中去。

client 支持:Perl 和 Python

注意:从 scroll 请求返回的结果反映了 search 发生时刻的索引状态,就像一个快照。后续的对文档的改动(索引、更新或者删除)都只会影响后面的搜索请求。

为了使用 scroll,初始搜索请求应该在查询中指定 scroll 参数,这可以告诉 Elasticsearch 需要保持搜索的上下文环境多久(参考Keeping the search context alive),如 ?scroll=1m

POST /twitter/tweet/_search?scroll=1m
{
"query": {
"match" : {
"title" : "elasticsearch"
}
}
}

使用上面的请求返回的结果中包含一个 scroll_id,这个 ID 可以被传递给 scroll API 来检索下一个批次的结果。

POST /_search/scroll
{
"scroll" : "1m",
"scroll_id" : "c2Nhbjs2OzM0NDg1ODpzRlBLc0FXNlNyNm5JWUc1"
}
  • GET 或者 POST 可以使用
  • URL不应该包含 index 或者 type 名字——这些都指定在了原始的 search 请求中。
  • scroll 参数告诉 Elasticsearch 保持搜索的上下文等待另一个 1m
  • scroll_id 参数

每次对 scroll API 的调用返回了结果的下一个批次知道没有更多的结果返回,也就是直到 hits 数组空了。

为了向前兼容,scroll_idscroll 可以放在查询字符串中传递。scroll_id 则可以在请求体中传递。

curl -XGET 'localhost:9200/_search/scroll?scroll=1m' -d 'c2Nhbjs2OzM0NDg1ODpzRlBLc0FXNlNyNm5JWUc1'

注意:初始搜索请求和每个后续滚动请求返回一个新的 _scroll_id,只有最近的 _scroll_id 才能被使用。

如果请求指定了聚合(aggregation),仅仅初始搜索响应才会包含聚合结果。

使用 scroll-scan 的高效滚动

使用 from and size 的深度分页,比如说 ?size=10&from=10000 是非常低效的,因为 100,000 排序的结果必须从每个分片上取出并重新排序最后返回 10 条。这个过程需要对每个请求页重复。

scroll API 保持了那些已经返回记录结果,所以能更加高效地返回排序的结果。但是,按照默认设定排序结果仍然需要代价。

一般来说,你仅仅想要找到结果,不关心顺序。你可以通过组合 scrollscan 来关闭任何打分或者排序,以最高效的方式返回结果。你需要做的就是将 search_type=scan 加入到查询的字符串中:

POST /twitter/tweet/_search?scroll=1m&search_type=scan
{
"query": {
"match" : {
"title" : "elasticsearch"
}
}
}
  • 设置 search_typescan 可以关闭打分,让滚动更加高效。

扫描式的滚动请求和标准的滚动请求有四处不同:

  • 不算分,关闭排序。结果会按照在索引中出现的顺序返回。
  • 不支持聚合
  • 初始 search 请求的响应不会在 hits 数组中包含任何结果。第一批结果就会按照第一个 scroll 请求返回。
  • 参数 size 控制了每个分片上而非每个请求的结果数目,所以 size10 的情况下,如果命中了 5 个分片,那么每个 scroll 请求最多会返回 50 个结果。

如果你想支持打分,即使不进行排序,将 track_scores 设置为 true

保持搜索上下文存活

参数 scroll (传递给 search 请求还有每个 scroll 请求)告诉 Elasticsearch 应该需要保持搜索上下文多久。这个值(比如说 1m,详情请见the section called “Time units)并不需要长到可以处理所有的数据——仅仅需要足够长来处理前一批次的结果。每个 scroll 请求(包含 scroll 参数)设置了一个新的失效时间。

一般来说,背后的合并过程通过合并更小的分段创建更大的分段来优化索引,同时会删除更小的分段。这个过程在滚动时进行,但是一个打开状态的搜索上下文阻止了旧分段在使用的时候不会被删除。这就是 Elasticsearch 能够不管后续的文档的变化,返回初始搜索请求的结果的原因。

保持旧的分段存活意味着会产生更多的文件句柄。确保你配置了节点有空闲的文件句柄。参考File Descriptors

你可以检查有多少搜索上下文开启了,

GET /_nodes/stats/indices/search?pretty

清除 scroll API

搜索上下文当 scroll 超时就会自动移除。但是保持 scroll 存活需要代价,如在前一节讲的那样,所以 scrolls 当scroll不再被使用的时候需要被用 clear-scroll 显式地清除:

DELETE /_search/scroll
{
"scroll_id" : ["c2Nhbjs2OzM0NDg1ODpzRlBLc0FXNlNyNm5JWUc1"]
}

多个 scroll ID 可按照数据传入:

DELETE /_search/scroll
{
"scroll_id" : ["c2Nhbjs2OzM0NDg1ODpzRlBLc0FXNlNyNm5JWUc1", "aGVuRmV0Y2g7NTsxOnkxaDZ"]
}

所有搜索上下文可以通过 _all 参数而清除:

DELETE /_search/scroll/_all

scroll_id 也可以使用一个查询字符串的参数或者在请求的body中传递。多个scroll ID 可以使用逗号分隔传入:

DELETE /_search/scroll/DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ==,DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAABFmtSWWRRWUJrU2o2ZExpSGJCVmQxYUEAAAAAAAAAAxZrUllkUVlCa1NqNmRMaUhiQlZkMWFBAAAAAAAAAAIWa1JZZFFZQmtTajZkTGlIYkJWZDFhQQAAAAAAAAAFFmtSWWRRWUJrU2o2ZExpSGJCVmQxYUEAAAAAAAAABBZrUllkUVlCa1NqNmRMaUhiQlZkMWFB

Sliced Scroll

对于返回大量文档的滚动查询,可以将滚动分割为多个切片,可以单独使用:

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"
}
}
}

  切片的id

  最大切片数

每个滚动都是独立的,可以像任何滚动请求一样并行处理。第一个请求的结果返回属于第一个slice(id:0)的文档,第二个请求的结果返回属于第二个slice的文档。由于最大切片数设置为2,因此两个请求的结果的并集等效于没有切片的滚动查询的结果。默认情况下,首先在shard集合上进行分割,然后在每个shard上使用_uid字段在本地进行分割,其公式如下: slice(doc) = floorMod(hashCode(doc._uid), max) 例如,如果shard数等于2且用户请求4个slice,则分配片0和2到第一个shard,切片1和3分配给第二个shard。

如果slice的数量大于shard的数量,则切片过滤器在第一次调用时非常慢,它具有O(N)的复杂度,并且存储器成本等于每个slice的N倍,其中N是在shard中的文档的总数。在几次调用之后,缓存过滤器在后续调用应该更快,但是您应该限制并行执行的切片查询的数量以避免内存溢出。

为了完全避免这种成本,可以使用doc_values另一个字段来进行切片,但用户必须确保该字段具有以下属性:

  • 该字段是数字。
  • doc_values 在该字段上启用
  • 每个文档都应包含单个值。如果文档具有指定字段的多个值,则使用第一个值。
  • 创建文档时永远不会更新每个文档的值。这可确保每个切片获得确定性结果。
  • 该领域的基数应该很高。这可确保每个切片获得大致相同数量的文档。
GET /twitter/_search?scroll=1m
{
"slice": {
"field": "date",
"id": 0,
"max": 10
},
"query": {
"match" : {
"title" : "elasticsearch"
}
}
}

对于仅附加基于时间的索引,timestamp可以安全地使用该字段。

默认情况下,每个滚动允许的最大切片数限制为1024.您可以更新index.max_slices_per_scroll索引设置以绕过此限制。

elasticsearch 深入 —— Scroll滚动查询的更多相关文章

  1. Elasticsearch系列---搜索执行过程及scroll游标查询

    概要 本篇主要介绍一下分布式环境中搜索的两阶段执行过程. 两阶段搜索过程 回顾我们之前的CRUD操作,因为只对单个文档进行处理,文档的唯一性很容易确定,并且很容易知道是此文档在哪个node,哪个sha ...

  2. Elasticsearch from/size-浅分页查询-深分页 scroll-深分页search_after深度查询区别使用及应用场景

    Elasticsearch调研深度查询 1.from/size 浅分页查询 一般的分页需求我们可以使用from和size的方式实现,但是这种的分页方式在深分页的场景下应该是避免使用的.深分页的页次增加 ...

  3. es的scoll滚动查询技术

    如果一次性要查出来比如10万条数据,那么性能会很差,此时一般会采取用scoll滚动查询,一批一批的查,直到所有数据都查询完处理完 使用scoll滚动搜索,可以先搜索一批数据,然后下次再搜索一批数据,以 ...

  4. Elasticsearch Sliced Scroll分页检索案例分享

    面试:你懂什么是分布式系统吗?Redis分布式锁都不会?>>>   The best elasticsearch highlevel java rest api-----bboss ...

  5. ElasticSearch7.3学习(二十二)----Text字段排序、Scroll分批查询场景解析

    1.Text字段排序 场景:数据库中按照某个字段排序,sql只需写order by 字段名即可,如果es对一个text field进行排序,es中无法排序.因为文档入倒排索引表时,分词存入,es无法知 ...

  6. ElasticSearch第四步-查询详解

    ElasticSearch系列学习 ElasticSearch第一步-环境配置 ElasticSearch第二步-CRUD之Sense ElasticSearch第三步-中文分词 ElasticSea ...

  7. Elasticsearch Span Query跨度查询

    ES基于Lucene开发,因此也继承了Lucene的一些多样化的查询,比如本篇说的Span Query跨度查询,就是基于Lucene中的SpanTermQuery以及其他的Query封装出的DSL,接 ...

  8. ElasticSearch(6)-结构化查询

    引用:ElasticSearch权威指南 一.请求体查询 请求体查询 简单查询语句(lite)是一种有效的命令行_adhoc_查询.但是,如果你想要善用搜索,你必须使用请求体查询(request bo ...

  9. Elasticsearch java api 常用查询方法QueryBuilder构造举例

    转载:http://m.blog.csdn.net/u012546526/article/details/74184769 Elasticsearch java api 常用查询方法QueryBuil ...

随机推荐

  1. c# 匿名委托

    using System; namespace AnonymousMethod { delegate void ArithmeticOperation(double operand1, double ...

  2. less:运算

    less中的运算 -任何数字.颜色或者变量都可以参加运算,运算应该被包裹在括号中. -例如:+-*. @width: 30px; .box { width: (20 + 5) * @width; } ...

  3. python的次方操作

    好简单,不需要import任何包 b=a**n就是求a的n次方,如果n=0.5就是开方 如果开方的是负数或者附复数,需要 import math b=math.sqrt(a) 这样

  4. centos6.5安装nginx1.16.0

    参考:   centos7 编译安装nginx1.16.0( 完整版 ) https://blog.csdn.net/weixin_37773766/article/details/80290939  ...

  5. C++创建对象时什么时候用*,什么时候不用*

    用*, 表示创建的是一个指针对象,而指针的创建,必须初始化,C++中用new关键字开辟内存. 另外指针对象访问成员变量用-> , 非指针用. 就这么个原则 但是指针也可以不用-> 例如 ( ...

  6. php strchr()函数 语法

    php strchr()函数 语法 作用:搜索字符串在另一字符串中的第一次出现.直线电机哪家好 语法:strchr(string,search,before_search); 参数: 参数 描述 st ...

  7. github配置和使用

    通过手册指导生产ssh key或取已有的ssh key root@iZwz93telmwbh624e5zetqZ:~# ls -al ~/.ssh total drwx------ root root ...

  8. Gym - 101194H Great Cells

    Problem H. Great Cells 题目链接:https://codeforces.com/gym/101194/attachments Input file: Standard Input ...

  9. POJ 3728 The merchant (树形DP+LCA)

    题目:https://vjudge.net/contest/323605#problem/E 题意:一棵n个点的树,然后有m个查询,每次查询找(u->v)路径上的两个数,a[i],a[j],(i ...

  10. Java 设计模式之 Command 设计模式

    首先我们先来看 UML 图: 参考资料: java设计模式-Command(命令)模式 - - ITeye技术网站http://men4661273.iteye.com/blog/1633775 JA ...