美文网首页
二十七、ElasticSearch聚合分析中的算法讲解

二十七、ElasticSearch聚合分析中的算法讲解

作者: 书写只为分享 | 来源:发表于2019-12-09 23:23 被阅读0次

    1、易并行聚合算法,三角选择原则,近似聚合算法
    (1)、易并行聚合算法:比如max


    图片1.png

    (2)、不易的,如count(distinct)


    图片2.png
    (3)、产生的三角选择原则
    精准+实时+大数据 --> 选择2个
    (1)精准+实时: 没有大数据,数据量很小,那么一般就是单击跑,随便你则么玩儿就可以

    (2)精准+大数据:hadoop,批处理,非实时,可以处理海量数据,保证精准,可能会跑几个小时
    (3)大数据+实时:es,不精准,近似估计,可能会有百分之几的错误率
    (4)、近似聚合算法
    如果采取近似估计的算法:延时在100ms左右,0.5%错误
    如果采取100%精准的算法:延时一般在5s~几十s,甚至几十分钟,几小时, 0%错误
    2、cardinality去重及算法优化和HLL算法分析
    es,去重,cartinality metric,对每个bucket中的指定的field进行去重,取去重后的count,类似于count(distcint)

    GET /tvs/sales/_search
    {
      "size":0, 
      "aggs": {
        "name_1": {
          "date_histogram": {
            "field": "sold_date",
            "interval": "month",
            "format": "yyyy-MM-dd"
          },
          "aggs": {
            "distinct_1": {
              "cardinality": {
                "field": "brand",
    "precision_threshold": 100
              }
            }
          }
        }
      }
    }
    

    precision_threshold优化准确率和内存开销可以提高去重性能
    cardinality算法,会占用precision_threshold * 8 byte 内存消耗,100 * 8 = 800个字节
    HyperLogLog++ (HLL)算法性能优化
    默认情况下,发送一个cardinality请求的时候,会动态地对所有的field value,取hash值; 将取hash值的操作,前移到建立索引的时候

    PUT /tvs/
    {
      "mappings": {
        "sales": {
          "properties": {
            "brand": {
              "type": "text",
              "fields": {
                "hash": {
                  "type": "murmur3" 
                }
              }
            }
          }
        }
      }
    }
    

    3、percentiles百分比算法以及网站访问时延统计
    需求:比如有一个网站,记录下了每次请求的访问的耗时,需要统计tp50,tp90,tp99
    tp50:50%的请求的耗时最长在多长时间
    tp90:90%的请求的耗时最长在多长时间
    tp99:99%的请求的耗时最长在多长时间

    数据:

    PUT /website/logs/_bulk
    { "index": {}}
    { "latency" : 105, "province" : "江苏", "timestamp" : "2016-10-28" }
    { "index": {}}
    { "latency" : 83, "province" : "江苏", "timestamp" : "2016-10-29" }
    { "index": {}}
    { "latency" : 92, "province" : "江苏", "timestamp" : "2016-10-29" }
    { "index": {}}
    { "latency" : 112, "province" : "江苏", "timestamp" : "2016-10-28" }
    { "index": {}}
    { "latency" : 68, "province" : "江苏", "timestamp" : "2016-10-28" }
    { "index": {}}
    { "latency" : 76, "province" : "江苏", "timestamp" : "2016-10-29" }
    { "index": {}}
    { "latency" : 101, "province" : "新疆", "timestamp" : "2016-10-28" }
    { "index": {}}
    { "latency" : 275, "province" : "新疆", "timestamp" : "2016-10-29" }
    { "index": {}}
    { "latency" : 166, "province" : "新疆", "timestamp" : "2016-10-29" }
    { "index": {}}
    { "latency" : 654, "province" : "新疆", "timestamp" : "2016-10-28" }
    { "index": {}}
    { "latency" : 389, "province" : "新疆", "timestamp" : "2016-10-28" }
    { "index": {}}
    { "latency" : 302, "province" : "新疆", "timestamp" : "2016-10-29" }
    

    不同概率百分比之间的防问效率:

    GET /website/logs/_search
    {
      "size": 0,
      "aggs": {
        "percen_1": {
          "percentiles": {
            "field": "latency",
            "percents": [
              50, 95,99
            ]
          }
        },
        "avg_1":{
          "avg": {
            "field": "latency"
          }
        }
        }
    }
    

    分组统计防问百分比,并计算平均值

    GET /website/logs/_search
    {
      "size": 0,
      "aggs": {
        "group_prov": {
          "terms": {
            "field": "province"
          },
          "aggs": {
            "per_1": {
              "percentiles": {
                "field": "latency",
                "percents": [
                  50,95,99
                ]
              }
            },
            "avg_1":{
              "avg": {
                "field": "latency"
              }
            }
          }
        }
      }
    }
    

    4、percentile ranks网站访问时延SLA统计

    SLA:就是你提供的服务的标准
    例以地区分组,计算以不同时间的响应百分比

    GET /website/logs/_search
    {
      "size": 0,
      "aggs": {
        "group_pr": {
          "terms": {
            "field": "province"
          },
          "aggs": {
            "per_renks": {
              "percentile_ranks": {
                "field": "latency",
                "values": [
                  200,
                  1500
                ]
              }
            }
          }
        }
      }
    }
    

    5、doc value原理
    (1)index-time生成
    PUT/POST的时候,就会生成doc value数据,也就是正排索引
    (2)核心原理与倒排索引类似
    正排索引,也会写入磁盘文件中,os cache先进行缓存,以提升访问doc value正排索引的性能,如果os cache内存大小不足够放得下整个正排索引,doc value,就会将doc value的数据写入磁盘文件中
    (3)性能问题:
    es官方是建议,es大量是基于os cache来进行缓存和提升性能的,不建议用jvm内存来进行缓存,那样会导致一定的gc开销和oom问题给jvm更少的内存,给os cache更大的内存。
    (4)、column压缩
    doc1: 550
    doc2: 550
    doc3: 500
    合并相同值,550,doc1和doc2都保留一个550的标识即可
    (1)所有值相同,直接保留单值
    (2)少于256个值,使用table encoding模式:一种压缩方式
    (3)大于256个值,看有没有最大公约数,有就除以最大公约数,然后保留这个最大公约数
    (4)如果没有最大公约数,采取offset结合压缩的方式:
    如果的确不需要doc value,比如聚合等操作,那么可以禁用,减少磁盘空间占用
    PUT my_index
    {
    "mappings": {
    "my_type": {
    "properties": {
    "my_field": {
    "type": "keyword"
    "doc_values": false
    }
    }
    }
    }
    }
    6、对于分词的field执行aggregation,发现报错。。。

    PUT /test_index/test_type/1
    {
    “test_field”:”test”
    }
    
    GET /test_index/test_type/_search 
    {
      "aggs": {
        "group_by_test_field": {
          "terms": {
            "field": "test_field"
          }
        }
      }
    }
    

    如果直接对分词field执行聚合,报错,大概意思是说,你必须要打开fielddata,然后将正排索引数据加载到内存中,才可以对分词的field执行聚合操作,而且会消耗很大的内存

    给分词的field,设置fielddata=true,发现可以执行

    POST /test_index/_mapping/test_type 
    {
      "properties": {
        "test_field": {
          "type": "text",
          "fielddata": true
        }
      }
    }
    

    也可以用内置field不分词,对string field进行聚合

    GET /test_index/test_type/_search 
    {
      "size": 0,
      "aggs": {
        "group_by_test_field": {
          "terms": {
            "field": "test_field.keyword"
          }
        }
      }
    }
    

    7、分词field+fielddata的工作原理
    (1)、不分词的所有field,可以执行聚合操作 --> 如果你的某个field不分词,那么在index-time时,就会自动生成doc value --> 针对这些不分词的field执行聚合操作的时候,自动就会用doc value来执行
    (2)、分词field,是没有doc value的。在index-time,如果某个field是分词的,那么是不会给它建立doc value正排索引的,因为分词后,占用的空间过于大,所以默认是不支持分词field进行聚合的
    fielddata加载到内存的过程是lazy加载的,对一个analzyed field执行聚合时,才会加载,而且是field-level加载的。一个index的一个field,所有doc都会被加载,而不是少数doc,不是index-time创建,是query-time创建
    为什么fielddata必须在内存?因为分词的字符串,需要按照term进行聚合,需要执行更加复杂的算法和操作,如果基于磁盘和os cache,那么性能会很差。

    8、fielddata相关优化配置
    (1)、内存限制
    indices.fielddata.cache.size: 20%,超出限制,清除内存已有fielddata数据,fielddata占用的内存超出了这个比例的限制,那么就清除掉内存中已有的fielddata数据
    默认无限制,限制内存使用,但是会导致频繁evict和reload,大量IO性能损耗,以及内存碎片和gc

    (2)监控fielddata内存使用
    GET /_stats/fielddata?fields=*
    GET /_nodes/stats/indices/fielddata?fields=*
    GET /_nodes/stats/indices/fielddata?level=indices&fields=*

    (3)、circuit breaker断路器
    如果一次query load的feilddata超过总内存,就会oom --> 内存溢出
    circuit breaker会估算query要加载的fielddata大小,如果超出总内存,就短路,query直接失败
    indices.breaker.fielddata.limit:fielddata的内存限制,默认60%
    indices.breaker.request.limit:执行聚合的内存限制,默认40%
    indices.breaker.total.limit:综合上面两个,限制在70%以内

    (4)、fielddata filter的细粒度内存加载控制

    POST /test_index/_mapping/my_type
    {
      "properties": {
        "my_field": {
          "type": "text",
          "fielddata": { 
            "filter": {
              "frequency": { 
                "min":              0.01, 
                "min_segment_size": 500  
              }
            }
          }
        }
      }
    }
    

    min:仅仅加载至少在1%的doc中出现过的term对应的fielddata
    比如说某个值,hello,总共有1000个doc,hello必须在10个doc中出现,那么这个hello对应的fielddata才会加载到内存中来
    min_segment_size:少于500 doc的segment不加载fielddata
    加载fielddata的时候,也是按照segment去进行加载的,某个segment里面的doc数量少于500个,那么这个segment的fielddata就不加载

    (5)、fielddata预加载

    POST /test_index/_mapping/test_type
    {
      "properties": {
        "test_field": {
          "type": "string",
          "fielddata": {
            "loading" : "eager" 
          }
        }
      }
    }
    

    query-time的fielddata生成和加载到内存,变为index-time,建立倒排索引的时候,会同步生成fielddata并且加载到内存中来,这样的话,对分词field的聚合性能当然会大幅度增强
    (6)、global ordinal序号标记预加载

    有很多重复值的情况,会进行global ordinal标记
    doc1: status1
    doc2: status2
    doc3: status2
    doc4: status1

    status1 --> 0 status2 --> 1

    doc1: 0
    doc2: 1
    doc3: 1
    doc4: 0

    建立的fielddata也会是这个样子的,这样的好处就是减少重复字符串的出现的次数,减少内存的消耗

    POST /test_index/_mapping/test_type
    {
      "properties": {
        "test_field": {
          "type": "string",
          "fielddata": {
            "loading" : "eager_global_ordinals" 
          }
        }
      }
    }
    

    相关文章

      网友评论

          本文标题:二十七、ElasticSearch聚合分析中的算法讲解

          本文链接:https://www.haomeiwen.com/subject/bocsgctx.html