一、 要解决的问题

  1. search命中的记录特别多,使用from+size分页,直接触发了elasticsearch的max_result_window的最大值;
{
"error": {
"root_cause": [
{
"type": "query_phase_execution_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": "shirts",
"node": "OBkTpZcTQJ25kmlNZ6xyLg",
"reason": {
"type": "query_phase_execution_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": 500
}
  1. 将elasticsearch作为数据库使用,直接将max_result_window设置一个很大的值,但是数据量大了很影响查询性能;

二、elasticsearch支持的分页方式

elasticsearch提供了三种分页的查询方式,以支持不同的查询场景;

from + size

search after

scroll

以下测试使用的是 elasticsearch 6.8

三、 from + size 分页

from + size是使用最普遍的search分页方案;

from: 设置要返回第一条记录的相对位置,默认值为0;

size: 此次search返回的最大记录数量, 默认值为10;

我们可以直接从第11条记录开始,返回最多10条记录;

GET my_store_index/_search
{
"query": {
"match": {
"name": "bj"
}
},
"from": 10,
"size": 10
}

此种分页方式特点

  1. 特别适合随机获取记录,实现类似商用搜索引擎的分页功能;
  2. 由于from + size是无状态的,搜索的时候,每个分片都需要返回from + size条记录,最终将所有分片的记录进行合并再返回size条记录;
  3. 受限实现机制,越靠后的记录查询性能越差,故elasticsearch默认设置max_result_window=10000,如果from + size超过这个值就会报错;

四、search after

即使我们将max_result_window调整成一个更大的值,但是当我们命中的结果比较多的时候,使用from + size的分页效果就会比较差;

elasticsearch提供的search after可以帮助我们解决这个问题;search after可以利用请求中包含的上一页的信息来帮助查询下一页的记录;

起始搜索如下,需要添加sort字段,并使用id作为排序字段;这里的排序字段需要确保每个document都是不同的,这样才能确保排序的唯一性;

GET my_store_index/_search
{
"_source": false,
"query": {
"match": {
"name": "bj"
}
},
"size": 10,
"sort": [
{
"id": {
"order": "desc"
}
}
]
}

我们可以看到返回结果中包含了sort字段,里边包含了命中记录对应的sort的值;

{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 25,
"max_score" : null,
"hits" : [
{
"_index" : "my_store_index",
"_type" : "_doc",
"_id" : "f64cf9f4-db2b-4059-bf97-315fe95f233c",
"_score" : null,
"sort" : [
"f64cf9f4-db2b-4059-bf97-315fe95f233c"
]
}
]
}
}

我们使用上一个请求中的sort的值作为以下请求中search_after的参数,来查询下一页的数据;

GET my_store_index/_search
{
"_source": false,
"query": {
"match": {
"name": "bj"
}
},
"size": 10,
"search_after":["f64cf9f4-db2b-4059-bf97-315fe95f233c"],
"sort": [
{
"id": {
"order": "desc"
}
}
]
}

此种分页方式的特点

  1. 需要指定一个值唯一的排序字段,通过返回记录的sort值对应的记录作为from的记录;
  2. 此种分页查询方式也是无状态的,分页的时候需要依赖search_after参数作为起始点,这样就可以直接跳过已经获取过的记录;
  3. 可以通过当前时间点最后一条记录的sort值,同时通过size来控制同时获取多页的记录来实现简单的向后随机翻页;
  4. 需要记录已经加载的每页起始的sort值,可以实现前向的随机翻页;

我们分别使用from+size、search after查询第二个10000条记录,查看两者执行时间,可以发现search after快将近2s;

GET my_store_index/_search
{
"_source":["id"],
"query": {
"match_phrase_prefix": {
"deviceData.content": "us"
}
},
"size": 10000,
"from": 10000
} {
"took":8212,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"skipped":0,
"failed":0
},
"hits":{
"total":29908,
"max_score":97.09149
}
}
GET my_store_index/_search
{
"_source":["id"],
"query": {
"match_phrase_prefix": {
"deviceData.content": "us"
}
},
"size": 10000,
"sort": [
{
"id": {
"order": "desc"
}
}
],
"search_after":["aa877c87-bb08-4fbd-8a51-ed4ebaa57251"]
} {
"took":6320,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"skipped":0,
"failed":0
},
"hits":{
"total":29908,
"max_score":null
}
}

五、scroll

elasticsearch提供的scroll可以实现一个请求返回所有命中记录,我们可以使用类似关系数据库中的游标的方式来获取命中的记录; scroll并不是为了实现实时的搜索请求,更多的是为了处理大量的数据,尤其适合从某一个index进行重新索引;

为了使用scroll,我们需要在url里通过scroll指定elasticsearch需要保留搜索结果的时间;

GET my_store_index/_search?scroll=1m
{
"_source": false,
"query": {
"match": {
"name": "bj"
}
},
"size": 2
} {
"_scroll_id" : "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAb0Fk9Ca1RwWmNUUUoyNWttbE5aNnh5TGcAAAAAAAAG8xZPQmtUcFpjVFFKMjVrbWxOWjZ4eUxnAAAAAAAABvUWT0JrVHBaY1RRSjI1a21sTlo2eHlMZwAAAAAAAAb2Fk9Ca1RwWmNUUUoyNWttbE5aNnh5TGcAAAAAAAAG9xZPQmtUcFpjVFFKMjVrbWxOWjZ4eUxn",
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 25,
"max_score" : 3.5134304,
"hits" : [
]
}
}

我们使用上边请求返回的_scroll_id来获取下一页的数据;

GET _search/scroll
{
"scroll" : "1m",
"scroll_id" : "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAdlFk9Ca1RwWmNUUUoyNWttbE5aNnh5TGcAAAAAAAAHZhZPQmtUcFpjVFFKMjVrbWxOWjZ4eUxnAAAAAAAAB2cWT0JrVHBaY1RRSjI1a21sTlo2eHlMZwAAAAAAAAdoFk9Ca1RwWmNUUUoyNWttbE5aNnh5TGcAAAAAAAAHaRZPQmtUcFpjVFFKMjVrbWxOWjZ4eUxn"
}

此种分页方式的特点

  1. 首次查询通过query string参数指定scroll的时间,elasticsearch会自动生成一个scroll并返回对应的id;
  2. 此查询是一种有状态的查询,不会实时响应索引变化;
  3. 每次请求返回的记录数通过首次请求设置的size参数控制;
  4. 返回scroll对应的全部记录之后再查询就返回空数组;
  5. scroll参数控制每次请求之后elasticsearch保留scroll的时间;

最新文章

  1. Spring系列之AOP
  2. 关于@property()的那些属性及ARC简介
  3. sap 根据TOCE找 USER_EXIT
  4. RPC 原理的前生今世
  5. Android 判断用户2G/3G/4G移动数据网络
  6. BZOJ 1050
  7. 【原创】通俗易懂的讲解KMP算法(字符串匹配算法)及代码实现
  8. eclipse 上安装systemgui
  9. pygame学习资料
  10. Win7下用easyBCD引导安装Ubuntu15.04
  11. 玩了几天的ARToolKit
  12. 使用 https://git.io 缩短 a GitHub.com URL.
  13. java 关键字transient
  14. CentOS安装JDK-tar.gz文件
  15. [工作日志]2018-11-15 主要: 改bug
  16. 向Sql Server数据库插入中文时显示乱码的解决办法 (转)
  17. 华为交换机VRRP 综合配置示例
  18. P1503 鬼子进村
  19. print多重打印
  20. git如何生成单个文件的补丁

热门文章

  1. Chapter 21 G-Methods for Time-Varying Treatments
  2. Loss Landscape Sightseeing with Multi-Point Optimization
  3. java-git 暂存
  4. 01 Java基础
  5. Java Springboot webSocket简单实现,调接口推送消息到客户端socket
  6. Laravel Redis分布式锁的使用
  7. java运算符1
  8. [ vue ] Quasar封装q-dialog组件,在外层实现弹出框的开启和关闭
  9. react中create-react-app详情配置文档
  10. 通过js触发launch事件获取页面信息