zoukankan      html  css  js  c++  java
  • 54.string field聚合以及fielddata原理初探

    主要知识点:

    • 直接对分词的term进行聚合后果
    • 设置fielddata=true
    • 直接用.keyword进行聚合
    • doc value 的性能问题

         

    一、直接对分词的term进行聚合后果

       

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

       

    1、新建一条数据(隐式创建一个索引和type)

       

    POST /test_index/test_type/1

    {

    "test_field":"test"

    }

       

    2、进行聚合操作

       

    GET /test_index/test_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."

    }

       

    对分词的field直接执行聚合操作es会报错,错误信息中会说,必须要打开fielddata(fielddata=true),然后将正排索引数据加载到内存中,才可以对分词的field执行聚合操作,而且会消耗很大的内存

       

    二、设置fielddata=true

    1、给分词的field,设置fielddata=true

       

    POST /test_index/_mapping/test_type

    {

    "properties": {

    "test_field": {

    "type": "text",

    "fielddata": true

    }

    }

    }

       

    2、查看mapping

    GET /test_index/_mapping/test_type

       

    执行结果

    {

    "test_index": {

    "mappings": {

    "test_type": {

    "properties": {

    "test_field": {

    "type": "text",

    "fields": {

    "keyword": {

    "type": "keyword",

    "ignore_above": 256

    }

    },

    "fielddata": true

    }

    }

    }

    }

    }

    }

       

    3、再次执行聚合操作

    GET /test_index/test_type/_search

    {

    "size": 0,

    "aggs": {

    "group_by_test_field": {

    "terms": {

    "field": "test_field"

    }

    }

    }

    }

    执行结果如下:

    "aggregations": {

    "group_by_test_field": {

    "doc_count_error_upper_bound": 0,

    "sum_other_doc_count": 0,

    "buckets": [

    {

    "key": "test",

    "doc_count": 2

    }

    ]

    }

    }

    }

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

       

    三、直接用.keyword进行聚合

    1、使用内置field不分词,对string field进行聚合。在es新版本中,新对text的字段新建一个.keyword的字段,可以直接用这个字段进行聚合操作

       

    GET /test_index/test_type/_search

    {

    "size": 0,

    "aggs": {

    "group_by_test_field": {

    "terms": {

    "field": "test_field.keyword"

    }

    }

    }

    }

    执行结果如下:

    "aggregations": {

    "group_by_test_field": {

    "doc_count_error_upper_bound": 0,

    "sum_other_doc_count": 0,

    "buckets": [

    {

    "key": "test",

    "doc_count": 2

    }

    ]

    }

    }

    }

    可以看出此时就已经可以聚合。如果对不分词的field执行聚合操作,直接就可以执行,不需要设置fieldata=true

       

    四、分词field+fielddata的工作原理

    在es内部会对所有不分词的field建立doc value,这些不分词的field可以执行聚合操作,如果某一个field不分词,那么在新建index的时候就已经建立了doc value值,所以es针对不分词的field会自动使用doc value来执行聚合操作。

    对于分词field,是没有doc value的,在新建索引时,如果某个field是分词的,那么es是不会给它建立doc value正排索引的,因为分词后,占用的空间过于大,所以默认是不支持分词field进行聚合。对于分词field,必须打开和使用fielddata,完全存在于纯内存中结构和doc value类似,如果是ngram或者是大量term,那么必将占用大量的内存,性能会变的很差。

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

    为什么fielddata必须在内存?因为分词的字符串,需要按照term进行聚合,需要执行更加复杂的算法和操作,如果基于磁盘和os cache,那么性能会很差。

  • 相关阅读:
    angularjs中ng-repeat-start与ng-repeat-end用法实例
    随笔 javascript-抽象工厂模式
    VMware一些使用心得
    oracle 12c的数据库导进 11g
    架构师基本功:消息队列
    如何提高工作效率
    oracle 12c 13姨
    架构师基本功:SOA
    autofac如何注册静态方法里的接口对象
    发布Java桌面程序
  • 原文地址:https://www.cnblogs.com/liuqianli/p/8542065.html
Copyright © 2011-2022 走看看