zoukankan      html  css  js  c++  java
  • ElasticSearch分页

    from + size 浅分页

    "浅"分页可以理解为简单意义上的分页。它的原理很简单,就是查询前20条数据,然后截断前10条,只返回10-20的数据。这样其实白白浪费了前10条的查询。

    GET test_dev/_search
    {
      "query": {
        "bool": {
          "filter": [
            {
              "term": {
                "age": 28
              }
            }
          ]
        }
      },
      "size": 10,
      "from": 20,
      "sort": [
        {
          "timestamp": {
            "order": "desc"
          },
          "_id": {
            "order": "desc"
          }
        }
      ]
    }
    
    • 其中,from定义了目标数据的偏移值,size定义当前返回的数目。默认from为0,size为10,即所有的查询默认仅仅返回前10条数据。

    • 在这里有必要了解一下from/size的原理:因为es是基于分片的,假设有5个分片,from=100,size=10。则会根据排序规则从5个分片中各取回100条数据,然后汇总成500条数据后选择最前面的10条数据。

    • 做过测试,越往后的分页,执行的效率越低。总体上会随着from的增加,消耗时间也会增加。而且数据量越大,就越明显

    scroll 深分页

    from+size查询在10000-50000条数据(1000到5000页)以内的时候还是可以的,但是如果数据过多的话,就会出现性能问题。
    为了解决此问题,elasticsearch提出了一个scroll滚动的方式。
    scroll 类似于sql中的cursor,使用scroll,每次只能获取一页的内容,然后会返回一个scroll_id。根据返回的这个scroll_id可以不断地获取下一页的内容,所以scroll并不适用于有跳页的情景。

    GET test_dev/_search?scroll=5m
    {
      "query": {
        "bool": {
          "filter": [
            {
              "term": {
                "age": 28
              }
            }
          ]
        }
      },
      "size": 10,
      "from": 0,
      "sort": [
        {
          "timestamp": {
            "order": "desc"
          },
          "_id": {
            "order": "desc"
          }
        }
      ]
    }
    
    • scroll=5m表示设置scroll_id保留5分钟可用。
    • 使用scroll必须要将from设置为0。
    • size决定后面每次调用_search搜索返回的数量
    • 通过数据返回的_scroll_id读取下一页内容,每次请求将会读取下10条数据,直到数据读取完毕或者scroll_id保留时间截止
    GET _search/scroll
    {
      "scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAJZ9Fnk1d......",
      "scroll": "5m"
    }
    

    注意:请求的接口不再使用索引名了,而是 _search/scroll,其中GET和POST方法都可以使用。

    • scroll删除
      根据官方文档的说法,scroll的搜索上下文会在scroll的保留时间截止后自动清除,但是我们知道scroll是非常消耗资源的,所以一个建议就是当不需要了scroll数据的时候,尽可能快的把scroll_id显式删除掉。

    清除指定的scroll_id:

    DELETE _search/scroll/DnF1ZXJ5VGhlbkZldGNo.....
    

    清除所有的scroll:

    DELETE _search/scroll/_all
    

    search_after 深分页

    scroll 的方式,官方的建议不用于实时的请求(一般用于数据导出),因为每一个 scroll_id 不仅会占用大量的资源,而且会生成历史快照,对于数据的变更不会反映到快照上。

    search_after 分页的方式是根据上一页的最后一条数据来确定下一页的位置,同时在分页请求的过程中,如果有索引数据的增删改查,这些变更也会实时的反映到游标上。但是需要注意,因为每一页的数据依赖于上一页最后一条数据,所以无法跳页请求。

    为了找到每一页最后一条数据,每个文档必须有一个全局唯一值,官方推荐使用 _uid 作为全局唯一值,其实使用业务层的 id 也可以。

    GET test_dev/_search
    {
      "query": {
        "bool": {
          "filter": [
            {
              "term": {
                "age": 28
              }
            }
          ]
        }
      },
      "size": 20,
      "from": 0,
      "sort": [
        {
          "timestamp": {
            "order": "desc"
          },
          "_id": {
            "order": "desc"
          }
        }
      ]
    }
    
    • 使用search_after必须要设置from=0。
    • 这里我使用timestamp和_id作为唯一值排序。
    • 我们在返回的最后一条数据里拿到sort属性的值传入到search_after。

    使用sort返回的值搜索下一页:

    GET test_dev/_search
    {
      "query": {
        "bool": {
          "filter": [
            {
              "term": {
                "age": 28
              }
            }
          ]
        }
      },
      "size": 10,
      "from": 0,
      "search_after": [
        1541495312521,
        "d0xH6GYBBtbwbQSP0j1A"
      ],
      "sort": [
        {
          "timestamp": {
            "order": "desc"
          },
          "_id": {
            "order": "desc"
          }
        }
      ]
    }
    

    修改默认分页限制值10000

    可以使用下面的方式来改变ES默认深度分页的index.max_result_window 最大窗口值

    curl -XPUT http://127.0.0.1:9200/my_index/_settings -d '{ "index" : { "max_result_window" : 500000}}'
    

    其中my_index为要修改的index名,500000为要调整的新的窗口数。将该窗口调整后,便可以解决无法获取到10000条后数据的问题。

    注意事项
    通过上述的方式解决了我们的问题,但也引入了另一个需要我们注意的问题,窗口值调大了后,虽然请求到分页的数据条数更多了,但它是用牺牲更多的服务器的内存、CPU资源来换取的。要考虑业务场景中过大的分页请求,是否会造成集群服务的OutOfMemory问题。

    获取总数据量

    修改最大限制值之后确实可以使from+size查询到更后面页的数据(10000之后),但是每次查询得到的总数量最大任然是10000,要想获取大于1万的查询数据量,可以分两步查询,第一步使用scroll查询获取总数据量;第二步使用from+size查询每页的数据,并设置分页。这样即解决了from+size无法查询10000之后的数据,也解决了scroll无法跳页的问题。

    使用scroll可能遇到的问题:

    Caused by: org.elasticsearch.ElasticsearchException: Trying to create too many scroll contexts.
     Must be less than or equal to: [500]. 
    This limit can be set by changing the [search.max_open_scroll_context] setting.
    
    • 这个报错是从es的日志文件中查出来的,大致意思是:尝试创建更多的scroll对象失败了,scroll对象总数量应该控制在500以内。可修改search.max_open_scroll_context的值来改变500这个阈值。
    • 原因:通过scroll 深分页可知道,es服务端会在内存中生成一个scroll_id对象,并会为该值指定过期时间,翻页的时候使用scroll_id来获取下一页的数据。默认情况下,一个实例下面仅可以创建最多500个scroll上下文对象,也就是500个scroll_id。报此错误的原因就是创建scroll上下文对象失败,因为当前已经存在500个这样的对象了。
    • 解决办法:
      • 通过观察可以发现,即使不做任何的处理,过一会就又可以发起scroll请求了,这是因为时间超过了scroll生命周期时间,scroll对象自己死掉了一些。
      • 按照提示说的,修改search.max_open_scroll_context的值
    put   http://{{es-host}}/_cluster/settings
    {
        "persistent": {
            "search.max_open_scroll_context": 5000
        },
        "transient": {
            "search.max_open_scroll_context": 5000
        }
    }
    
    • 在使用完scroll_id之后立即调用删除接口,删除该scroll对象

    引用

    • 互联网...
  • 相关阅读:
    adb logcat 基本用法
    系统广播 android.intent.action.KILL_BACKGROUND_SERVICE
    eclipse android 不会自动生成R.java文件和包的解决办法
    android sdk 镜像点
    android ant 自动编译打包
    java spring 框架学习
    android机型排行榜(201509)
    转: Jenkins+Gradle实现android开发持续集成、打包
    android app多渠道分发打包
    转: 从微信的故障谈谈服务可用性
  • 原文地址:https://www.cnblogs.com/Naylor/p/13202939.html
Copyright © 2011-2022 走看看