ElasticSearch 分页查询

Elasticsearch分页查询

在默认情况下, Elasticsearch 查询返回前10条匹配的文档。

为了对大批量查询结果分页,最简单方式是在查询API中添加from和size参数,from表示需要返回的满足查询条件的数量,size表示查询起始数据在全量结果集中的偏移量。
创建实验索引:

PUT linked_blog
{
  "mappings": {
    "default": {
      "properties": {
         "title": {
            "type": "text",
            "analyzer" : "ik_max_word",
            "search_analyzer" : "ik_smart",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
      }
    }
  }
}
GET /linked_blog/default/_search
{
 "query": {
   "match_all": {}
 },
 "from": 3, 
 "size": 2
}

默认情况下,使用from+size参数不能分页查询超过10,000的文档。该限制可以通过索引设置index.max_result_window更改。
深度分页可能造成慢查询。查询结果在返回之前会被排序。但查询通常会跨越多个分片,每个分片先自各执行查询,并各自排序,再将各个分片查询结果合并以保证最终查询结果顺序正确。

为了避免该问题,Elasticsearch官方推荐使用 scroll 或者 search_after替代from+size实现分页。
Elasticsearch的查询是分2个阶段进行的,即Query阶段和Fetch阶段。 Query阶段比较轻量级,通过查询倒排索引,获取满足查询结果的文档ID列表。 而Fetch阶段比较重,需要将每个shard的结果取回。
Scroll查询,先做轻量级的Query阶段以后,免去了繁重的全局排序过程。 它只是将查询结果集,也就是文档ID列表保留在一个上下文里, 之后分批Fetch。
Scroll查询方式类似于传统数据库的游标查询和Redis的scan查询。如果使用过Twitter开发者API会发现,这种方式和使用Twitter开发者API获取博文也很类似。

为了使用scroll,只需在首次分页查询时加上scroll参数,其值为该查询上下文存活时间。例如:

GET /linked_blog/default/_search?scroll=1m
{
 "query": {
   "match_all": {}
 },
 "size": 3
}

上面的查询结果中回包含_scroll_id字段。

{
  "_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAARo3hFkVENTdJaTEtUXJhX21hREhweVRaeHcAAAAAACs9lRY4aFpJa0dTRlQ0T2dLWVNxRFNQWFBBAAAAAAAx4D8WQXhkeGc4Ri1UTlc2a1N3OFAtTWVVUQAAAAAARo3iFkVENTdJaTEtUXJhX21hREhweVRaeHcAAAAAAAA9FxZzNnZWQ3duSlF2aTE5bHBUd2ZyN0RB",
  "took": 4580,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 12,
    "max_score": 1,
    "hits": [
      {
        "_index": "linked_blog",
        "_type": "default",
        "_id": "AXTPePEMqi9OmRTyD92V",
        "_score": 1,
        "_source": {
          "title": "MyBatis如何调用mysql数据库存储过程"
        }
      },
      {
        "_index": "linked_blog",
        "_type": "default",
        "_id": "AXTPdUHfqi9OmRTyD92C",
        "_score": 1,
        "_source": {
          "title": "oracle数据库创建表空间、创建用户、用户赋权限"
        }
      },
      {
        "_index": "linked_blog",
        "_type": "default",
        "_id": "AXTPe6oYqi9OmRTyD92m",
        "_score": 1,
        "_source": {
          "title": "Nginx+Tomcat——负载均衡与动静分离群集 理论知识+实验部署+报错排坑 详细讲解一看秒懂!!!"
        }
      }
    ]
  }
}

后面的分页使用scroll查询,并带上上次查询结果的_scroll_id字段。直到hits数组空,即表示所有数据查询完成。

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

结果如下

{
  "_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAARo3hFkVENTdJaTEtUXJhX21hREhweVRaeHcAAAAAACs9lRY4aFpJa0dTRlQ0T2dLWVNxRFNQWFBBAAAAAAAx4D8WQXhkeGc4Ri1UTlc2a1N3OFAtTWVVUQAAAAAARo3iFkVENTdJaTEtUXJhX21hREhweVRaeHcAAAAAAAA9FxZzNnZWQ3duSlF2aTE5bHBUd2ZyN0RB",
  "took": 1911,
  "timed_out": false,
  "terminated_early": true,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 12,
    "max_score": 1,
    "hits": [
      {
        "_index": "linked_blog",
        "_type": "default",
        "_id": "AXTPfEmrqi9OmRTyD92p",
        "_score": 1,
        "_source": {
          "title": "Nginx+Tomcat高可用负载均衡群集——动静分离"
        }
      },
      {
        "_index": "linked_blog",
        "_type": "default",
        "_id": "AXTPc15Qqi9OmRTyD911",
        "_score": 1,
        "_source": {
          "title": "关于MeterSphere的性能测试架构理解"
        }
      },
      {
        "_index": "linked_blog",
        "_type": "default",
        "_id": "AXTPd6q0qi9OmRTyD92Q",
        "_score": 1,
        "_source": {
          "title": "利用HikariCP大幅提升性能"
        }
      }
    ]
  }
}

初次分页和后面每次分页均返回_scroll_id。 尽管_scroll_id在两次请求之间可能会发生变化,但并非总是会发生变化。在任何情况下,都应使用最近收到的_scroll_id。

scroll 在首次分页时就已经将所有满足查询条件的文档确定了,并忽略后续对这些文档的修改(可以理解,Elasticsearch使用版本号区分修改)。并在首次分页时,查询上下文也已经创建了,在后续分页中可以通过scroll_id 区分该查询上下文,并使其保持存活状态。

scroll 参数的值告诉Elasticsearch 查询上下文存活时间。该值并非处理所有分页数据所需时间,而是处理当前页所需时间,每次分页都会重新设置查询上下文过期时间。如果一个scroll 请求没有设置scroll 参数,则表示该查询上下文将会被释放。

使用如下接口,可以查询每个节点打开了多少scroll 查询上下文。

GET /_nodes/stats/indices/search

scroll 查询上下文在存活时间到达后会被自动删除。因为scroll 查询上下文需要消耗资源,所以当分页结束或者不再需要分页时,需要及时手动关闭。手动关闭API如下:

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

关闭多个scroll 查询上下文可用如下API:

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

如下API可以清除所有scroll 查询上下文:

DELETE /_search/scroll/_all
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值