zoukankan      html  css  js  c++  java
  • ES使用中遇到的坑

    1.ES分页超过10000条报错

    es 默认采用的分页方式是 from+ size 的形式,是一种逻辑上的分页,在深度分页的情况下,采用from,to方式进行分页效率会非常的低,例如以下查询

    1 GET /student/_doc/_search
    2 {
    3   "query":{
    4     "match_all": {}
    5   },
    6   "from":5000,
    7   "size":10
    8 }
    

    ES并不是单纯的查询5000-5010这10条数据,而是在各个分片上匹配排序并得到5010条数据,协调节点拿到这些数据再进行排序等处理,然后结果集中取最后10条数据返回。随着分页深度的加深,ES的分页效率会越来越低,甚至OOM。

    ES为了性能默认情况下限制了分页的深度,如果不做任何配置,ES只能查询前10000条数据,也就是 max_result_window = 10000。如果分页到10000条数据以上,ES会报错。

    解决方法:

    • 调大max_result_window的值
    • 使用scroll进行分页
    • 使用search_after进行分页(官方推荐)

    2.ES 返回结果total始终是10000

          1 {
          2   "took" : 48,
          3   "timed_out" : false,
          4   "_shards" : {
          5     "total" : 1,
          6     "successful" : 1,
          7     "skipped" : 0,
          8     "failed" : 0
          9   },
         10   "hits" : {
         11     "total" : {
         12       "value" : 1000,
         13       "relation" : "eq"
         14     },
         15     "max_score" : null,
         16     "hits" : [
         17       {
         18         "_index" : "bank",
         19         "_type" : "_doc",
         20         "_id" : "0",
         21         "_score" : null,
         22         "_source" : {
         23           "account_number" : 0,
         24           "balance" : 16623,
         25           "firstname" : "Bradshaw"
         34         },
         35         "sort" : [
         36           0
         37         ]
         38       },
    
    

    如上是是Es一次普通查询返回的结果集

    • hits 用来实际搜索结果集
    • hits.total 是包含与搜索条件匹配的文档总数信息的对象
    • hits.total.value 表示总命中计数的值(必须在hits.total.relation上下文中解释)

    要注意的是hits.total.value返回的值不一定是准确的,默认情况下,hits.total.value是不确切的命中计数,在这种情况下,当hits.total.relation的值是eq时,hits.total.value的值是准确计数。当hits.total.relation的值是gte时,hits.total.value的值是不准确的。需要设置track_total_hits为true,才能使hits.total.value的结果准确

    1 GET /student/_doc/_search
    2 {
        "track_total_hits":true;
    3   "query":{
    4     "match_all": {}
    5   },
    6   "size":0
    7 }
    

    当然如要统计文档数量我们更推荐使用count,而不是通过hits.total.value来表示.

    参数track_total_hits可以控制total值的准确性,可以设为false、true或正整数。

    • 当为false时,不再返回total计数,total始终为1;
    • 当为正整数时,表示精确的命中文档计数,例如为1000时,此时如果命中结果小于或等于1000时,value是精确的计数,relation是eq,如果命中的结果数大于了1000时,此时value等于1000,relation是gte,如果需要精确统计结果数,这个值要设置的很大或者设为true
    • 当track_total_hits设置为true时,hits.total.value的值始终是准确的但是会影响查询性能。

    3.terms分桶聚合结果不准确

    ES基于分布式,每一个搜索请求都是分发到所有的分片上单独处理,最后汇总结果。聚合也是这样操作。

    在 Terms Aggregation 的返回中有两个特殊的数值

    • doc_count_error_upper_bound:被遗漏的 term 分桶包含的文档有可能的最大值,也就是没有在这次聚合中返回,但是可能存在的潜在聚合的值。
    • sum_other_doc_count: 处理返回结果 bucket 的 terms 以外,其他 terms 的文档总数(总数 -返回的总数),这次聚合中没有统计到的文档数。

    因为ES为分布式部署,不同文档分散于多个分片,这样当聚合时,会在每个分片上分别聚合,然后由协调节点汇总结果后返回。聚合结果会按照value从高到低进行排序。terms聚合也可以指定一个size,表示返回聚合的数量,如果设置size为3,则表示返回value排名前三的结果,这时每个分片都只聚合了本分片中排名前三的桶。其他没有统计到的文档数由每个节点返回后,汇总为此元素。sum_other_doc_count显示多少,就表示有多少个文档没有参与此次聚合。所以terms聚合并不是准确的聚合

    解决

    • 当数据量大时,可以不设置分片,所有数据在一个分片上
    • 聚合时调大shard_size 参 数,降低 doc_count_error_upper_bound 来提升准确度默认shard_size = size *1.5 +10
    • size调大,提高聚合结果的数量,可以保证结果近似准确。

    4.ES时间类型的查询和存储问题

    在Elasticsearch内部,不论 date 是什么展示格式,所有date类型数据(时间字符串 or 时间戳等)在 Elasticsearch 内部存储时全部都会转换成 UTC时间戳(并且把时区也会计算进去),最后以milliseconds-since-the-epoch 作为存储的格式。date类型字段上的查询会在内部被转为对long型值的范围查询,查询的结果类型是字符串。

    • GMT:格林威治标准时间
    • UTC:世界协调时间
    • DST:夏日节约时间
    • CST:中国标准时间

    具体细节参照博客https://blog.csdn.net/lijingjingchn/article/details/106925871

    我们的项目中为了避免时区问题用到了两种方案

    • ES中Data类型的数据指定格式化方式,数据存入ES使用 字符串的日期时间,查询ES也直接使用字符串的日期时间

      PUT  test-date
      {
        "mappings": {
          "time": {
            "properties": {
              "date": {
                "type": "date",
                "format": "yyyy-MM-dd HH:mm:ss"
              }
            }
          }
        }
      }
      
      POST test-date/time/1
      {
          "date":"2017-09-15 14:50:16"
      }
      
      
      GET test-date/time/_search
      {
        "query":{
          "term": {
            "date": {
              "value": "2017-09-15 14:50:16"
            }
          }
        }
      }
      
    • ES的日期时间使用long类型的时间戳存储,日期时间类型的数据存入ES先用Java将其转为时间戳再存入ES。同样查询时也将日期时间转为时间戳再进行查询

  • 相关阅读:
    vi/vim 文字处理器常用命令
    图片在容器里水平垂直居中
    谁的属性值优先被访问
    创建对象和实例
    碎碎念css
    未整理js
    表格<table>
    盒子模型
    Css文件目录结构
    链接文字<a>保持原有的字体颜色
  • 原文地址:https://www.cnblogs.com/myblogstart/p/15718104.html
Copyright © 2011-2022 走看看