Elasticsearch进阶笔记第二十六篇

242 阅读4分钟

Elasticsearch高手进阶篇(53)

深入聚合数据分析_doc value机制内核级原理深入探秘

doc value原理

  • index-time生成

    • PUT/POST的时候,就会生成doc value数据,也就是正排索引
  • 核心原理与倒排索引类似

    • 正排索引,也会写入磁盘文件中,然后呢,os cache先进行缓存,以提升访问doc value正排索引的性能
    • 如果os cache内存大小不足够放得下整个正排索引,doc value,就会将doc value的数据写入磁盘文件中
  • 性能问题

    • 给jvm更少内存,64g服务器,给jvm最多16g

es官方是建议,es大量是基于os cache来进行缓存和提升性能的,不建议用jvm内存来进行缓存,那样会导致一定的gc开销oom问题

  • 给jvm更少的内存,给os cache更大的内存
  • 64g服务器,给jvm最多16g,几十个g的内存给os cache
  • os cache可以提升doc value和倒排索引的缓存和查询效率

column压缩

  • doc1: 550
  • doc2: 550
  • doc3: 500

合并相同值,550,doc1和doc2都保留一个550的标识即可

  • 所有值相同,直接保留单值
  • 少于256个值,使用table encoding模式:一种压缩方式
  • 大于256个值,看有没有最大公约数,有就除以最大公约数,然后保留这个最大公约数
  • 如果没有最大公约数,采取offset结合压缩的方式
  • doc1: 36
  • doc2: 24

6 --> doc1: 6, doc2: 4 --> 保留一个最大公约数6的标识,6也保存起来

disable doc value

如果的确不需要doc value,比如聚合等操作,那么可以禁用,减少磁盘空间占用

 PUT /waws_index
 {
   "mappings": {
     "my_type": {
       "properties": {
         "my_field": {
           "type":"keyword"
           "doc_values": false 
         }
       }
     }
   }
 }

Elasticsearch高手进阶篇(54)

深入聚合数据分析_string field聚合实验以及fielddata原理初探

  • 插入测试数据
 PUT /waws_index_1/waws_type/1
 {
   "test_field":"test"
 }

对于分词的field执行aggregation,发现报错

 GET /waws_index_1/waws_type/_search 
 {
   "aggs": {
     "group_by_test_field": {
       "terms": {
         "field": "test_field"
       }
     }
   }
 }
 
 {
   "error": {
     "root_cause": [
       {
         "type": "illegal_argument_exception",
         "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [test_field] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory."
       }
     ],
     "type": "search_phase_execution_exception",
     "reason": "all shards failed",
     "phase": "query",
     "grouped": true,
     "failed_shards": [
       {
         "shard": 0,
         "index": "waws_index_1",
         "node": "w85Pu0ftS7-vrZOwmdAE9g",
         "reason": {
           "type": "illegal_argument_exception",
           "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [test_field] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory."
         }
       }
     ],
     "caused_by": {
       "type": "illegal_argument_exception",
       "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [test_field] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory."
     }
   },
   "status": 400
 }
  • 对分词的field,直接执行聚合操作,会报错,大概意思是说,你必须要打开fielddata,然后将正排索引数据加载到内存中,才可以对分词的field执行聚合操作,而且会消耗很大的内存

给分词的field,设置fielddata=true

 POST /waws_index_1/_mapping/waws_type 
 {
   "properties": {
     "test_field": {
       "type": "text",
       "fielddata": true
     }
   }
 }
  • 查看test_field
 GET /waws_index_1/_mapping/waws_type 
 
 {
   "waws_index_1": {
     "mappings": {
       "waws_type": {
         "properties": {
           "test_field": {
             "type": "text",
             "fields": {
               "keyword": {
                 "type": "keyword",
                 "ignore_above": 256
               }
             },
             "fielddata": true
           }
         }
       }
     }
   }
 }
  • 搜索field
 GET /waws_index_1/waws_type/_search 
 {
   "size": 0, 
   "aggs": {
     "group_by_test_field": {
       "terms": {
         "field": "test_field"
       }
     }
   }
 }
 
 {
   "took": 75,
   "timed_out": false,
   "_shards": {
     "total": 5,
     "successful": 5,
     "failed": 0
   },
   "hits": {
     "total": 1,
     "max_score": 0,
     "hits": []
   },
   "aggregations": {
     "group_by_test_field": {
       "doc_count_error_upper_bound": 0,
       "sum_other_doc_count": 0,
       "buckets": [
         {
           "key": "test",
           "doc_count": 1
         }
       ]
     }
   }
 }

如果要对分词的field执行聚合操作,必须将fielddata设置为true

使用内置field不分词,对string field进行聚合

 GET /waws_index_1/waws_type/_search 
 {
   "size": 0,
   "aggs": {
     "group_by_test_field": {
       "terms": {
         "field": "test_field.keyword"
       }
     }
   }
 }
 ​
 {
   "took": 17,
   "timed_out": false,
   "_shards": {
     "total": 5,
     "successful": 5,
     "failed": 0
   },
   "hits": {
     "total": 1,
     "max_score": 0,
     "hits": []
   },
   "aggregations": {
     "group_by_test_field": {
       "doc_count_error_upper_bound": 0,
       "sum_other_doc_count": 0,
       "buckets": [
         {
           "key": "test",
           "doc_count": 1
         }
       ]
     }
   }
 }

如果对不分词的field执行聚合操作,直接就可以执行,不需要设置fieldata=true

分词field+fielddata的工作原理

  • doc value --> 不分词的所有field,可以执行聚合操作 --> 如果你的某个field不分词,那么在index-time,就会自动生成doc value --> 针对这些不分词的field执行聚合操作的时候,自动就会用doc value来执行

  • 分词field,是没有doc value的,在index-time,如果某个field是分词的,那么是不会给它建立doc value正排索引的,因为分词后,占用的空间过于大,所以默认是不支持分词field进行聚合的

分词field默认没有doc value,所以直接对分词field执行聚合操作,是会报错的

对于分词field,必须打开和使用fielddata,完全存在于纯内存中 ,结构和doc value类似。如果是ngram或者是大量term,那么必将占用大量的内存

如果一定要对分词的field执行聚合,那么必须将fielddata=true,然后es就会在执行聚合操作的时候,现场将field对应的数据,建立一份fielddata正排索引,fielddata正排索引的结构跟doc value是类似的,但是只会讲fielddata正排索引加载到内存中来,然后基于内存中的fielddata正排索引执行分词field的聚合操作

  • 如果直接对分词field执行聚合,报错,才会让我们开启fielddata=true,告诉我们,会将fielddata uninverted index,正排索引,加载到内存,会耗费内存空间

  • 为什么fielddata必须在内存?

    • 因为大家自己思考一下,分词的字符串,需要按照term进行聚合,需要执行更加复杂的算法和操作,如果基于磁盘和os cache,那么性能会很差