**ES 不能查询1万条以后的数据**

Written with StackEdit.

ES 不能查询1万条以后的数据

官网说了,有两种解决办法:

  • search_after

  • scroll

##search_after的方式

{
  "query": {
    "match_all": {}
  },
  "from": 9996,
  "size": 5
}
这样查会报错的,from+size超过10000了。

我们使用search_after。 在使用之前我们需要指定一个unique的字段来排序,推荐使用_uid。

{
  "query": {
    "match_all": {}
  },
  "sort": {
    "_uid": "desc"
  },
  "from": 9995,
  "size": 5
}

这样查询之后返回的结果里就有sort了。

{
    "_index":"datasmart",
    "_type":"repo",
    "_id":"AV5hAJfo_7uB9S_OJQL_",
    "_score":null,
    "_source":{
        "3_t":"mhizam.doe",
        "dataType":1,
        "dataSource":23,
        "1_t":"Muhammad Hizam bin Mohd Ibrahim",
        "5_date":1465780654000
    },
    "sort":[
        "repo#AV5hAJfo_7uB9S_OJQL_"
    ]
}

从最后一个文档里取出sort的值,从10001条数据开始,我们用search_after来查。

{
  "query": {
    "match_all": {}
  },
  "sort": {
    "_uid": "desc"
  },
  "search_after": [
    "repo#AV5hAJfo_7uB9S_OJQL_"
  ],
  "from": -1,
  "size": 5
}

注意加上search_after之后, from 的值要设置成0或者-1。

这样我们就将第10001-10005条数据拿出来了,然后我们取出第10005条数据的_uid。把它放在search_after里就可以查出10005之后的数据了。如此循环就能拿出所有数据了。

限制:
不能自由的跳转到任意一页。但是能同时进行多个查询
它跟scroll的方式差不多,但是不同之处是search_after是无状态的,它总是针对最新版本的搜索进行解析,所以在遍历的时候排序可能会发生变化,这就要看索引的有没有更新和删除操作了。


##scroll的方式

第一次查的时候需要在query string上指定scroll这个参数。 这个参数的意思是告诉ES,“搜索上下文” 应该存活多长时间

注意scroll是有状态的。比如第一次查询的时候根据检索条件查到了2万个文档。在之后scroll的过程中,就算有人添加了几个文档, scroll还是认为只有2万个文档。

curl -XPOST '192.168.40.11:9200/datasmart/repo/_search?scroll=1m&pretty' -H 'Content-Type: application/json' -d'
{
    "from":9995,
    "size": 5,
    "query": {
        "match_all" : {}
    }
}
'

返回的结果里有一个_scroll_id,下一次查询时要把这个值带上。

{
  "_scroll_id" : "DnF1ZXJ5VGhlbkZldGNoAwAAAAAAAChBFk05TnNyQnFCVHpXS2pqVE1TRlBrVkEAAAAAAAAoQBZNOU5zckJxQlR6V0tqalRNU0ZQa1ZBAAAAAAAAKEIWTTlOc3JCcUJUeldLampUTVNGUGtWQQ==",
  "took" : 8,
  "timed_out" : false,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "failed" : 0
  },
  "hits" : {
    "total" : 639306,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "datasmart",
        "_type" : "repo",
        "_id" : "AV5WWzBd_7uB9S_OFqo3",
        "_score" : 1.0,
        "_source" : {
          "description" : "Key Distribution Center Service Account",
          "displayName" : null
        }
      },
      ...
    ]
  }
}

拿出接下来的5条数据:
检索条件第一次查询的时候已经定了,这里就不需要加任何检索条件了。
这样看来,使用scroll的方式要判断一下,当from+size超过1万条的时候才开始scroll。一旦滚动起来,这个size是不可更改的。所以到1万的时候要不要考虑一下把size的值改大,或者改小。

注意这个时候url里也不能再有index和type name了。scorll:1m表示 让ES把搜索上下文再保活1分钟。
由于每一次请求都会设置一个新的失效时间,所以一般情况下这个值不需要设置的太大。

curl -XPOST '192.168.40.11:9200/_search/scroll?pretty' -H 'Content-Type: application/json' -d'
{
    "scroll" : "1m", 
    "scroll_id" : "DnF1ZXJ5VGhlbkZldGNoAwAAAAAAAChBFk05TnNyQnFCVHpXS2pqVE1TRlBrVkEAAAAAAAAoQBZNOU5zckJxQlR6V0tqalRNU0ZQa1ZBAAAAAAAAKEIWTTlOc3JCcUJUeldLampUTVNGUGtWQQ==" 
}
'

返回接下来的5条数据:

{
  "_scroll_id" : "DnF1ZXJ5VGhlbkZldGNoAwAAAAAAAChBFk05TnNyQnFCVHpXS2pqVE1TRlBrVkEAAAAAAAAoQBZNOU5zckJxQlR6V0tqalRNU0ZQa1ZBAAAAAAAAKEIWTTlOc3JCcUJUeldLampUTVNGUGtWQQ==",
  "took" : 1,
  "timed_out" : false,
  "terminated_early" : true,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "failed" : 0
  },
  "hits" : {
    "total" : 639306,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "datasmart",
        "_type" : "repo",
        "_id" : "AV5WWzBd_7uB9S_OFqpD",
        "_score" : 1.0,
        "_source" : {
          "description" : null,
          "displayName" : "Microsoft Exchange Approval Assistant"
        }
      },
      ...
    ]
  }
}

scroll 完毕我们还要把搜索上下文清除,一般不需要刻意清除,因为失效时间一到,ES会自动清除搜索上下文。

查看所有搜索上下文:

curl -XGET '192.168.40.11:9200/_nodes/stats/indices/search?pretty'

清除scroll:

curl -XDELETE '192.168.40.11:9200/_search/scroll?pretty' -H 'Content-Type: application/json' -d'
{
    "scroll_id" : ["DnF1ZXJ5VGhlbkZldGNoAwAAAAAAAChBFk05TnNyQnFCVHpXS2pqVE1TRlBrVkEAAAAAAAAoQBZNOU5zckJxQlR6V0tqalRNU0ZQa1ZBAAAAAAAAKEIWTTlOc3JCcUJUeldLampUTVNGUGtWQQ=="]
}
'
方括号里可以填入多个scroll id.

清除所有scroll:

curl -XDELETE '192.168.40.11:9200/_search/scroll/_all?pretty'

Sliced Scroll

如果文档数太多的话,可以将scroll切分成多片。
感觉全库导出的时候用这个比较好。这个其实就是多个scroll同时跑而已,用法上跟scroll几乎一模一样。

发2次请求得到两个scroll_id, 然后每个slice使用自己的scroll_id去读即可。

curl -XGET '192.168.40.11:9200/datasmart/repo/_search?scroll=1m&pretty' -H 'Content-Type: application/json' -d'
{
    "slice": {
        "id": 0, 
        "max": 2 
    },
    "query": {
        "match_all" : {}
    }
}
'

curl -XGET '192.168.40.11:9200/datasmart/repo/_search?scroll=1m&pretty' -H 'Content-Type: application/json' -d'
{
    "slice": {
        "id": 1,
        "max": 2
    },
    "query": {
        "match_all" : {}
    }
}
'

注意 如果slice的个数比 shards的个数大。 那么第一次调用的时候, slice filter会非常慢。调用几次后, filter应该已经被缓存了,所以接下来的调用应该会快很多。 但是你应该限制 同时跑slice的个数以避免内存爆炸。

你可能感兴趣的:(ES)