Skip to main content

滚动查询 scroll

Scroll API

Scroll API 通常用于翻页查询,其方式与在传统数据库中使用游标的方式大致相同,首先从第一次滚动查询获取结果及scroll_id。

参数 scroll=1m 保持scroll上下文1分钟

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

上述请求的结果包括一个_scroll_id,它应该传递给滚动API,以便检索下一批结果。

POST /_search/scroll 
{
"scroll" : "1m",
"scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ=="
}

query参数

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

排序参数

info

sort 会将结果集排序,但也会影响查询效率。

GET /_search?scroll=1m
{
"sort": [
"_doc"
]
}

清除scroll上下文

保持滚动打开是有代价的,因此,一旦不再使用滚动,应使用clear scroll API明确清除滚动

DELETE /_search/scroll
{
"scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ=="
}

清除多个scroll上下文

DELETE /_search/scroll
{
"scroll_id" : [
"DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ==",
"DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAABFmtSWWRRWUJrU2o2ZExpSGJCVmQxYUEAAAAAAAAAAxZrUllkUVlCa1NqNmRMaUhiQlZkMWFBAAAAAAAAAAIWa1JZZFFZQmtTajZkTGlIYkJWZDFhQQAAAAAAAAAFFmtSWWRRWUJrU2o2ZExpSGJCVmQxYUEAAAAAAAAABBZrUllkUVlCa1NqNmRMaUhiQlZkMWFB"
]
}

清除所有scroll上下文

DELETE /_search/scroll/_all

Sliced Scroll

如果 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: 切片的 id
  • max: 最大切片数量

上面的例子,第一个请求返回的是第一个切片(id : 0)的文档,第二个请求返回的是第二个切片的文档。因为我们设置了最大切片数量是 2 ,所以两个请求的结果等价于一次不切片的 scroll 查询结果。默认情况下,先在第一个分片(shard)上做切分,然后使用以下公式:slice(doc) = floorMod(hashCode(doc._uid), max) 在每个 shard 上执行切分。例如,如果 shard 的数量是 2 ,并且用户请求 4 slices ,那么 id 为 0 和 2 的 slice 会被分配给第一个 shard ,id 为 1 和 3 的 slice 会被分配给第二个 shard 。

每个 scroll 是独立的,可以像任何 scroll 请求一样进行并行处理。

note

如果 slices 的数量比 shards 的数量大,第一次调用时,slice filter 的速度会非常慢。它的复杂度时 O(n) ,内存开销等于每个 slice N 位,其中 N 时 shard 中的文档总数。经过几次调用后,筛选器会被缓存,后续的调用会更快。但是仍需要限制并行执行的 sliced 查询的数量,以免内存激增。

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

该字段是数字类型 该字段启用了 doc_values 每个文档应当包含单个值。如果一份文档有指定字段的多个值,则使用第一个值 每个文档的值在创建文档时设置了之后不再更新,这可以确保每个切片获得确定的结果 字段的基数应当很高,这可以确保每个切片获得的文档数量大致相同

GET /twitter/_search?scroll=1m
{
"slice": {
"field": "date",
"id": 0,
"max": 10
},
"query": {
"match" : {
"title" : "elasticsearch"
}
}
}
note

默认情况下,每个 scroll 允许的最大切片数量时 1024。你可以更新索引设置中的 index.max_slices_per_scroll 来绕过此限制。