从一个分页问题开始

做分页查询,当分页达到一定量的时候,报如下错误

Result window is too large, from + size must be less than or equal to: [10000] but was [78020]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting.

解决方案

  • 在业务中限制分页大小,使from+size<=10000;
  • 动态更改索引设置,为max_result_window参数赋值足够大的值。
PUT index/_settings
{
"index":{
"max_result_window":50000
}
}

推荐使用第一种解决方案,因为es的优势在于搜索,不在于分页,对此做限制就是为不影响其性。就es的默认配置,假设每页10条记录,也有1000页,如果业务上实在不妥协,则使用第二种方案。

溯源

以上解决方案均是基于max_result_window=10000来进行展开的。那么为什么ES官方会有此参数的限制呢?

max_result_window的值可以无限制修改吗?接下来做个简单示例:

场景复现

新建测试库(PUT请求)

localhost:9200/chenjun_test_01/_bulk?refresh
{ "index" : { "_id" : 1 } }
{ "name" : "百里守约","type":1}
{ "index" : { "_id" : 2 } }
{ "name" : "凯","type":2}
{ "index" : { "_id" : 3 } }
{ "name" : "盾山", "type":3}

查询数据(GET请求)

http://127.0.0.1:9200/chenjun_test_01/_search

返回值:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "chenjun_test_01",
"_type": "_doc",
"_id": "1",
"_score": 1.0,
"_source": {
"name": "百里守约",
"type": 1
}
},
{
"_index": "chenjun_test_01",
"_type": "_doc",
"_id": "2",
"_score": 1.0,
"_source": {
"name": "凯",
"type": 2
}
},
{
"_index": "chenjun_test_01",
"_type": "_doc",
"_id": "3",
"_score": 1.0,
"_source": {
"name": "盾山",
"type": 3
}
}
]
}
}

模拟分页查询(正常查询)(GET请求):

http://127.0.0.1:9200/chenjun_test_01/_search
{
"from": 0,
"size": 1,
"query": {
"match_all": { }
}
} 返回值:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "chenjun_test_01",
"_type": "_doc",
"_id": "1",
"_score": 1.0,
"_source": {
"name": "百里守约",
"type": 1
}
}
]
}
}

测试临界值(GET请求):

http://127.0.0.1:9200/chenjun_test_01/_search

{
"from": 9990, //模拟第999页
"size": 10,// 查询10条
"query": {
"match_all": { }
}
} 返回结果:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 1.0,
"hits": []
}
} http://127.0.0.1:9200/chenjun_test_01/_search
{
"from": 10000, // 测试第1000页
"size": 1,// 查询1条
"query": {
"match_all": { }
}
}
返回结果:
{
"error": {
"root_cause": [
{
"type": "illegal_argument_exception",
"reason": "Result window is too large, from + size must be less than or equal to: [10000] but was [10001]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting."
}
],
"type": "search_phase_execution_exception",
"reason": "all shards failed",
"phase": "query",
"grouped": true,
"failed_shards": [
{
"shard": 0,
"index": "chenjun_test_01",
"node": "UuMcBk37TNWHjY4hVtzyVA",
"reason": {
"type": "illegal_argument_exception",
"reason": "Result window is too large, from + size must be less than or equal to: [10000] but was [10001]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting."
}
}
],
"caused_by": {
"type": "illegal_argument_exception",
"reason": "Result window is too large, from + size must be less than or equal to: [10000] but was [10001]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting.",
"caused_by": {
"type": "illegal_argument_exception",
"reason": "Result window is too large, from + size must be less than or equal to: [10000] but was [10001]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting."
}
}
},
"status": 400
}

此时,错误已经出现了,想必你有疑问,ES查一条数据都扛不住?不是号称海量数据引擎吗?先别急,这个我在后面再分析。

那么我们来验证解决方案的第二条,修改max_result_window的值,改成2万做个演示:

先检查下测试索引配置(GET请求):

http://127.0.0.1:9200/chenjun_test_01/_settings
返回值:
{
"chenjun_test_01": {
"settings": {
"index": {
"creation_date": "1673579058293",
"number_of_shards": "1",
"number_of_replicas": "1",
"uuid": "6F-jxX9VRCimqov4wR-eqg",
"version": {
"created": "7080199"
},
"provided_name": "chenjun_test_01"
}
}
}
}

修改配置(PUT请求)

http://127.0.0.1:9200/chenjun_test_01/_settings
{
"index":{
"max_result_window":20000
}
} 返回值:
{
"acknowledged": true
}

再查看下索引库配置信息(GET请求):

http://127.0.0.1:9200/chenjun_test_01/_settings

{
"chenjun_test_01": {
"settings": {
"index": {
"number_of_shards": "1",
"provided_name": "chenjun_test_01",
"max_result_window": "20000",
"creation_date": "1673579058293",
"number_of_replicas": "1",
"uuid": "6F-jxX9VRCimqov4wR-eqg",
"version": {
"created": "7080199"
}
}
}
}
}

可以看到,配置已经生效, "max_result_window": "20000"。

此时我们再去执行以下刚才的模拟分页查询(GET请求):

http://127.0.0.1:9200/chenjun_test_01/_search
返回值:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 1.0,
"hits": []
}
}

可以看到,查询确实不报错了。由此可见,修改max_result_window确实可以解决当前问题,但是,解决的也仅仅是当前的问题。当我们在生成环境中,随着业务增长,数据量增加,这个错误还会复现。

再次模拟分页,这次模拟从2000页开始,也只查询一条数据(GET请求)

http://127.0.0.1:9200/chenjun_test_01/_search
{
"from": 20000,
"size": 1,
"query": {
"match_all": { }
}
}
返回值:
{
"error": {
"root_cause": [
{
"type": "illegal_argument_exception",
"reason": "Result window is too large, from + size must be less than or equal to: [20000] but was [20001]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting."
}
],
"type": "search_phase_execution_exception",
"reason": "all shards failed",
"phase": "query",
"grouped": true,
"failed_shards": [
{
"shard": 0,
"index": "chenjun_test_01",
"node": "UuMcBk37TNWHjY4hVtzyVA",
"reason": {
"type": "illegal_argument_exception",
"reason": "Result window is too large, from + size must be less than or equal to: [20000] but was [20001]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting."
}
}
],
"caused_by": {
"type": "illegal_argument_exception",
"reason": "Result window is too large, from + size must be less than or equal to: [20000] but was [20001]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting.",
"caused_by": {
"type": "illegal_argument_exception",
"reason": "Result window is too large, from + size must be less than or equal to: [20000] but was [20001]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting."
}
}
},
"status": 400
}

看到了吧,也就是说一旦数据达到max_result_window窗口设的值,es就不给你查询了。现象已然清楚,那么让我们回到最初,为什么ES官方会有此参数的限制呢?

问题分析

max_result_window是分页返回的最大数值,因为ES是分布式的,数据散落在各个节点,当你查询分页数据的时候,比如每页500条数据,那么需要在每个Shard先进行排序,取前500条数据,最后把每个Shard的数据在JVM中汇总,再次排序,最后取前500。max_result_window本身是对JVM的一种保护,通过设定一个合理的阈值,避免初学者分页查询时由于单页数据过而导致OOM。很多人会告诉你如果想要增加单页数据的上限,放开这个参数就行,但是如果你不知道这个参数的意义,那么就会导致频分的内存溢出而且很难找到原因,设置一个合理的大小是需要通过你的各项参数来确定的,比如你用户量、数据量、物理内存的大小等等,通过监控数据和分析各项指标从而确定一个最佳值,并非越大约好,JVM不能超过物理内存的一半。

演示的时候,我特意模拟1000页开始和2000页开始只查一条数据,导致es查询崩盘的案例,可能这个对我们有疑问,ES不是号称海量数据杀手吗?怎么才几万数据查个一条就扛不住了,海量在哪?

这个就值得讨论一波的,es的海量体现在搜索上,而不是做分页操作上,Elasticsearch 是位于 Elastic Stack 核心的分布式搜索和分析引擎,它是搜索引擎,依靠的是其内部的倒排索引机制,仅仅是对海量数据的全文匹配来说,它是海量数据杀手的依据。而我们现在遇到的是深度分页问题,自然无法体现它的优势。

来看一下为什么我们深分页后,查一条数据为什么都不给查,说这个得拿es分布式存储系统中分页查询的过程来举例,假设在一个有 4 个主分片的索引中搜索,每页返回10条记录。当我们请求结果的第1页(结果从 1 到 10 ),每一个分片产生前 10 的结果,并且返回给 协调节点 ,协调节点对 40 个结果排序得到全部结果的前 10 个。当我们请求第 99 页(结果从 990 到 1000),需要从每个分片中获取满足查询条件的前1000个结果,返回给协调节点, 然后协调节点对全部 4000 个结果排序,获取前10个记录。当请求第10000页,每页10条记录,则需要先从每个分片中获取满足查询条件的前100010个结果,返回给协调节点。然后协调节点需要对全部(100010 * 分片数4)的结果进行排序,然后返回前10个记录。可以看到,在分布式系统中,对结果排序的成本随分页的深度成指数上升。

以上测试的例子中,表面上你分页从10000条开始,只查一条,实际上es需要查询from+size=10001条数据,然后再将那个1过滤给你。在数据量非常大的情况下,from+size分页会把全部记录加载到内存中,这样做不但运行速递特别慢,而且容易让es出现内存不足而挂掉。比如要取第1000页的数据,在分页的时候,es需要首先在每一个节点上取出10001的数据,然后对数据进行排序,取出排序后在10000到10001的数据,然后返回。这样随着数据量的增大,每次分页时排序的开销会越来越大。这就是 ES搜索引擎对任何查询都不要返回超过 10000 个结果的设的的原因。

分页方案

ES支持的三种分页查询方式

  • From + Size 查询
  • Scroll 遍历查询
  • Search After 查询

From + Size

es 默认采用的分页方式是 from+ size 的形式。

默认返回前10个匹配的匹配项。其中:
from:未指定,默认值是 0,注意不是1,代表当前页返回数据的起始值。
size:未指定,默认值是 10,代表当前页返回数据的条数。

优缺点

但是这种分页方式,随着深度分页的递进,对内存和查询效率是不友好的,在深度分页的情况下,这种使用方式效率是非常低的,除了效率上的问题,还有一个无法解决的问题是,es 目前支持最大的 skip 值是 max_result_window,默认为 10000 。也就是当 from + size > max_result_window 时,es 将返回错误。

官方建议:

1、避免过度使用 from 和 size 来分页或一次请求太多结果。
2、不推荐使用 from + size 做深度分页查询的核心原因:
搜索请求通常跨越多个分片,每个分片必须将其请求的命中内容以及任何先前页面的命中内容加载到内存中。
对于翻页较深的页面或大量结果,这些操作会显著增加内存和 CPU 使用率,从而导致性能下降或节点故障。

Scroll

有一种查询场景,我们需要一次性或者每次查询大量的文档,但是对实时性要求并不高。ES针对这种场景提供了scroll api的方案。这个方案牺牲了实时性,但是查询效率确实非常高。不要把 scroll用于实时请求,它主要用于大数据量的场景。例如:将一个索引的内容索引到另一个不同配置的新索引中。

测试查询(GET请求)

在请求后面追加scroll=1m参数,表示1分钟内有效
http://127.0.0.1:9200/chenjun_test_01/_search?scroll=1m
{
"size": 3, // 设置每页3条数据进行分页滚动查询
"query": {
"match_all" : {
}
}
} 返回结果:
{
"_scroll_id": "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFC05X1hxWVVCVUNTejNTcmFVMW5KAAAAAAAAAF0WVXVNY0JrMzdUTldIalk0aFZ0enlWQQ==",
"took": 5,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 23,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "chenjun_test_01",
"_type": "_doc",
"_id": "1",
"_score": 1.0,
"_source": {
"name": "百里守约",
"type": 1
}
},
{
"_index": "chenjun_test_01",
"_type": "_doc",
"_id": "2",
"_score": 1.0,
"_source": {
"name": "凯",
"type": 2
}
},
{
"_index": "chenjun_test_01",
"_type": "_doc",
"_id": "3",
"_score": 1.0,
"_source": {
"name": "盾山",
"type": 3
}
}
]
}
}

接下来继续查询,我们带上上一次查询结果返回的_scroll_id作为查询参数:

// 此时,可以不用指定索引库和查询条件了,直接使用scroll_id进行查询,1分钟内均有效
http://127.0.0.1:9200/_search/scroll
{
"scroll": "1m",
"scroll_id": "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFC05X1hxWVVCVUNTejNTcmFVMW5KAAAAAAAAAF0WVXVNY0JrMzdUTldIalk0aFZ0enlWQQ=="
} 返回值
{
"_scroll_id": "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFC05X1hxWVVCVUNTejNTcmFVMW5KAAAAAAAAAF0WVXVNY0JrMzdUTldIalk0aFZ0enlWQQ==",
"took": 20,
"timed_out": false,
"terminated_early": true,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 23,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "chenjun_test_01",
"_type": "_doc",
"_id": "4",
"_score": 1.0,
"_source": {
"name": "东皇太一",
"type": 1
}
},
{
"_index": "chenjun_test_01",
"_type": "_doc",
"_id": "5",
"_score": 1.0,
"_source": {
"name": "孙悟空",
"type": 2
}
},
{
"_index": "chenjun_test_01",
"_type": "_doc",
"_id": "6",
"_score": 1.0,
"_source": {
"name": "后裔",
"type": 3
}
}
]
}
}
可以看到获取到了第二页的数据,获得的结果里面包含有一个scoll_id,下一次再发送scoll请求的时候,必须带上这个scoll_id,接下来获取第三页数据。以此类推,后面每次滚屏都把前一个的scroll_id复制过来。注意到,后续请求时没有了index信息,size信息等,这些都在初始请求中,只需要使用scroll_id和scroll两个参数即可。

很多人对scroll这个参数容易混淆,误认为是查询的限制时间。这个理解是错误的。这个时间其实指的是es把本次快照的结果缓存起来的有效时间。scroll 参数相当于告诉了 ES我们的search context要保持多久,后面每个 scroll 请求都会设置一个新的过期时间,以确保我们可以一直进行下一页操作。

scroll这种方式为什么会比较高效
ES的检索分为查询(query)和获取(fetch)两个阶段,query阶段比较高效,只是查询满足条件的文档id汇总起来。fetch阶段则基于每个分片的结果在coordinating节点上进行全局排序,然后最终计算出结果。scroll查询的时候,在query阶段把符合条件的文档id保存在前面提到的search context里。 后面每次scroll分批取回只是根据scroll_id定位到游标的位置,然后抓取size大小的结果集即可,少了排序计算的过程,故而比较高效。

Scroll API 原理上是对某次查询生成一个游标 scroll_id , 后续的查询只需要根据这个游标去取数据,直到结果集中返回的 hits 字段为空,就表示遍历结束。scroll_id 的生成可以理解为建立了一个临时的历史快照,在此之后的增删改查等操作不会影响到这个快照的结果。

所有文档获取完毕之后,需要手动清理掉 scroll_id 。虽然es 会有自动清理机制,但是 srcoll_id 的存在会耗费大量的资源来保存一份当前查询结果集映像,并且会占用文件描述符。所以用完之后要及时清理。使用 es 提供的 CLEAR_API 来删除指定的 scroll_id

删除视图快照(DELETE请求)

http://127.0.0.1:9200/_search/scroll
{
"scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFC05X1hxWVVCVUNTejNTcmFVMW5KAAAAAAAAAF0WVXVNY0JrMzdUTldIalk0aFZ0enlWQQ=="
}

优缺点

scroll查询的相应数据是非实时的,scoll滚动搜索技术,一批一批查询。scoll搜索会在第一次搜索的时候,保存一个当时的视图快照,之后只会基于该旧的视图快照提供数据搜索,如果这个期间数据变更,是查询不到的,并且保留视图快照需要足够的堆内存空间。

官方文档强调:不再建议使用scroll API进行深度分页。如果要分页检索超过 Top 10,000+ 结果时,推荐使用:PIT + search_after。

适用场景

全量或数据量很大时遍历结果数据,而非分页查询。

search after

为社么会有 search_after?

官方的建议scroll 并不适用于实时的请求,因为每一个 scroll_id 不仅会占用大量的资源(特别是排序的请求),而且是生成的历史快照,对于数据的变更不会反映到快照上。这种方式往往用于非实时处理大量数据的情况,比如要进行数据迁移或者索引变更之类的。

那么在实时情况下如果处理深度分页的问题呢?
es 给出了 search_after 的方式,这是在 >= 5.0 版本才提供的功能。search after利用实时有游标来帮我们解决实时滚动的问题,简单来说前一次查询的结果会返回一个唯一的字符串,下次查询带上这个字符串,进行`下一页`的查询,一看觉得和Scroll差不多,search_after有点类似scroll,但是和scroll又不一样,它提供一个活动的游标,通过上一次查询最后一条数据来进行下一次查询。 基本思想:searchAfter的方式通过维护一个实时游标来避免scroll的缺点,它可以用于实时请求和高并发场景。

看下官方说明:

测试一下:

http://127.0.0.1:9200/chenjun_test_01/_search
{
"size": 2,
"query": {
"match": {
"type": "3"
}
},
"sort": [
{
"_id": "desc" // 由于我创建的索引库字段较少,没有唯一标识一条记录的字段,就按id来吧
}
]
}
返回值:
{
"took": 5,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 8,
"relation": "eq"
},
"max_score": null,
"hits": [
{
"_index": "chenjun_test_01",
"_type": "_doc",
"_id": "9",
"_score": null,
"_source": {
"name": "小乔",
"type": 3
},
"sort": [
"9"
]
},
{
"_index": "chenjun_test_01",
"_type": "_doc",
"_id": "6",
"_score": null,
"_source": {
"name": "后裔",
"type": 3
},
"sort": [
"6" // 注意这个老六,一会要用它
]
}
]
}
}

上面的请求会为每一个文档返回一个包含sort排序值的数组。这些sort排序值可以被用于 search_after 参数里以便抓取下一页的数据。比如,我们可以使用最后的一个文档的sort排序值,将它传递给 search_after 参数:

http://127.0.0.1:9200/chenjun_test_01/_search

{
"size": 2,
"query": {
"match": {
"type": "3"
}
},
"search_after": [6], //这个值与上次查询最后一条数据的sort值一致,支持多个
"sort": [
{
"_id": "desc"
}
]
} {
"took": 6,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 8,
"relation": "eq"
},
"max_score": null,
"hits": [
{
"_index": "chenjun_test_01",
"_type": "_doc",
"_id": "3",
"_score": null,
"_source": {
"name": "盾山",
"type": 3
},
"sort": [
"3"
]
},
{
"_index": "chenjun_test_01",
"_type": "_doc",
"_id": "22",
"_score": null,
"_source": {
"name": "宫本武藏",
"type": 3
},
"sort": [
"22"
]
}
]
}
}

官方提示:当我们使用search_after时,from值必须设置为0或者-1。

验证,以上查询条件我没写from,只写了size:2,默认from就是从0开始的。
http://127.0.0.1:9200/chenjun_test_01/_search
{
"from": 1,
"size": 2,
"query": {
"match": {
"type": "3"
}
},
"sort": [
{
"_id": "desc"
}
]
}
返回:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 8,
"relation": "eq"
},
"max_score": null,
"hits": [
{
"_index": "chenjun_test_01",
"_type": "_doc",
"_id": "6",
"_score": null,
"_source": {
"name": "后裔",
"type": 3
},
"sort": [
"6"
]
},
{
"_index": "chenjun_test_01",
"_type": "_doc",
"_id": "3",
"_score": null,
"_source": {
"name": "盾山",
"type": 3
},
"sort": [
"3"
]
}
]
}
} =========================================
上面第一次查询设置了从1开始,然后查2个,没问题,我们也能拿到上次最后一个数据的sort,即盾山的sort,接下来
我们按search_after调用规则来继续携带这个追加参数"search_after": ["3"]来请求。
http://127.0.0.1:9200/chenjun_test_01/_search
{"from":1,
"size": 2,
"query": {
"match": {
"type": "3"
}
},
"search_after": ["3"],
"sort": [
{
"_id": "desc"
}
]
} 返回结果:
{
"error": {
"root_cause": [
{
"type": "search_exception",
"reason": "`from` parameter must be set to 0 when `search_after` is used."
}
],
"type": "search_phase_execution_exception",
"reason": "all shards failed",
"phase": "query",
"grouped": true,
"failed_shards": [
{
"shard": 0,
"index": "chenjun_test_01",
"node": "UuMcBk37TNWHjY4hVtzyVA",
"reason": {
"type": "search_exception",
"reason": "`from` parameter must be set to 0 when `search_after` is used."
}
}
]
},
"status": 500
}
Search_after不是自由跳转到随机页面的解决方案,而是并行滚动许多查询。它与scroll API非常相似,但与之不同的是,search_after参数是无状态的,它总是针对最新版本的搜索器进行解析。因此,排序顺序可能会在遍历过程中根据索引的更新和删除而改变。

优缺点

很明显,Search_after的缺点就是不能自由跳页,search_after 查询仅支持向后翻页。不严格受制于 max_result_window,可以无限制往后翻页,单次请求值不能超过 max_result_window,但总翻页结果集可以超过,那自然就无法应用到业务中的分页查询了。

总结

分布式存储引擎的深度分页目前没有完美的解决方案。

比如针对百度、google这种全文检索的查询,通过From+ size返回Top 10000 条数据完全能满足使用需求,末尾查询评分非常低的结果一般参考意义都不大。

From+ size:需要随机跳转不同分页(类似主流搜索引擎)、Top 10000 条数据之内分页显示场景。

search_after:仅需要向后翻页的场景及超过Top 10000 数据需要分页场景。

Scroll:需要遍历全量数据场景 。

max_result_window:调大治标不治本,不建议调过大。

ES-分页查询的更多相关文章

  1. 分页查询es时,返回的数据不是自己所期望的问题

    在进行es分页查询时,一般都是用sql语句转成es查询字符串,在项目中遇到过不少次返回的数据不是自己所期望的那样时,多半原因是自己的sql拼接的有问题. 解决办法:务必要保证自己的sql语句拼接正确.

  2. ES 25 - Elasticsearch的分页查询及其深分页问题 (deep paging)

    目录 1 分页查询方法 2 分页查询的deep paging问题 1 分页查询方法 在GET请求中拼接from和size参数 // 查询10条数据, 默认从第0条数据开始 GET book_shop/ ...

  3. es的查询、排序查询、分页查询、布尔查询、查询结果过滤、高亮查询、聚合函数、python操作es

    今日内容概要 es的查询 Elasticsearch之排序查询 Elasticsearch之分页查询 Elasticsearch之布尔查询 Elasticsearch之查询结果过滤 Elasticse ...

  4. Elasticsearch——分页查询From&Size VS scroll

    Elasticsearch中数据都存储在分片中,当执行搜索时每个分片独立搜索后,数据再经过整合返回.那么,如果要实现分页查询该怎么办呢? 更多内容参考Elasticsearch资料汇总 按照一般的查询 ...

  5. ElasticSearch—分页查询

    ElasticSearch查询—分页查询详解 Elasticsearch中数据都存储在分片中,当执行搜索时每个分片独立搜索后,数据再经过整合返回.那么,如何实现分页查询呢? 按照一般的查询流程来说,如 ...

  6. ES 20 - 查询Elasticsearch中的数据 (基于DSL查询, 包括查询校验match + bool + term)

    目录 1 什么是DSL 2 DSL校验 - 定位不合法的查询语句 3 match query的使用 3.1 简单功能示例 3.1.1 查询所有文档 3.1.2 查询满足一定条件的文档 3.1.3 分页 ...

  7. ElasticSearch——分页查询

    前言 ElasticSearch实现分页查询,有3种方式,他们在数据查询中各自占据着不同的优势,因此在搜索引擎的数据分页过程中,如何更好地利用各自的优势来进行数据查询是一个非常重要的过程. 传统分页( ...

  8. elasticserach数据库深度分页查询的原理

    深度分页存在的问题 https://segmentfault.com/a/1190000019004316?utm_source=tag-newest 在实际应用中,分页是必不可少的,例如,前端页面展 ...

  9. Elasticsearch 分页查询

    目录 前言 from + size search after scroll api 总结 参考资料 前言 我们在实际工作中,有很多分页的需求,商品分页.订单分页等,在MySQL中我们可以使用limit ...

  10. ES 分页方案

    ES 中,存在三种常见的分页方案: FROM, SIZE Search-After Scroll 下面将依次比较三种方案之间的 trede-off,并给出相应建议的应用场景. 常见分页,FROM, S ...

随机推荐

  1. vscode环境配置(C/C++)

    一.MinGW和vscode的简单了解 1.MinGW是什么? MinGW(Minimalist GNU on Windows).它实际上是将经典的开源 C语言 编译器 GCC 移植到了 Window ...

  2. (二) MdbCluster分布式内存数据库——分布式架构1

    (二) MdbCluster分布式内存数据库--分布式架构1   分布式架构是MdbCluster的核心关键,业界有很多相关的实现,却很少有文章详细的解释每个架构实现背后的细节和这么做的原因.在Mdb ...

  3. kali linux破解wifi密码-超详细过程

    前期准备VMware Workstation虚拟机在虚拟机安装好kail linunx系统无线网卡(芯片为3070或者1887L都支持Linux)一.打开终端,用airmon-ng命令查看如果出现无法 ...

  4. C端自动化实现:appium+winappdriver+python

    一. 前言 有小伙伴有办公自动化的需求,特此出一篇C端自动化教程,并附带demo案例.C端的自动化比B端多一个appium,其他的操作大同小异. 二. 环境 appium:exe工具,用于启动服务,官 ...

  5. JZOJ 2022.07.18【提高组A】模拟

    \(\text{T1}\) 很容易想到用 \(f_1 f_2 ... f_k\) 来表示第 \(n\) 项 发现重点关注指数即可,即我们要递推 \(f_1 ... f_k\) 对应的指数 递推涉及 \ ...

  6. Iceberg 数据治理及查询加速实践

    数据治理 Flink 实时写入 Iceberg 带来的问题 在实时数据源源不断经过 Flink 写入的 Iceberg 的过程中,Flink 通过定时的 Checkpoint 提交 snapshot ...

  7. [EULAR文摘] 超声腱鞘炎对RA早期诊断的价值

    超声腱鞘炎对RA早期诊断的价值 Sahbudin I, et al. EULAR 2015. Present ID: OP0015. 背景:为了预测早期未分化疾病发展为类风湿关节炎(RA), EULA ...

  8. Activity 和 Fragment 中的视图绑定

    开启视图绑定 找到 build.gradle 文件,因为有两个 build.gradle,我们要操作的是第二个: 在这个位置加上这一句话,然后点击右上角的 Sync Now 按钮更新项目: andro ...

  9. Angular 发布IIS

    1.IIS服务器需要安装插件 安装 Url https://www.iis.net/downloads/microsoft/url-rewrite 2.修改配置 在src目录下,添加 web.conf ...

  10. python中的上下文管理器以及python内建模块contextlib的contextmanager方法

    上下文管理器 上下文管理器是实现了上下文管理协议的对象,其特有的语法是"with -as".主要用于保存和恢复各种全局状态,关闭文件等,并为try-except-finally提供 ...