博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Elasticsearch 聚合之 Terms
阅读量:4230 次
发布时间:2019-05-26

本文共 6514 字,大约阅读时间需要 21 分钟。

本篇着重讲解的 terms 聚合,它是按照某个字段中的值来分类:

比如性别有男、女,就会创建两个桶,分别存放男女的信息。默认会搜集 doc_count 的信息,即记录有多少男生,有多少女生,然后返回给客户端,这样就完成了一个 terms 的统计。

Terms 聚合

{    "aggs" : {        "genders" : {            "terms" : { "field" : "gender" }        }    }}

得到的结果如下:

{    ...    "aggregations" : {        "genders" : {            "doc_count_error_upper_bound": 0,             "sum_other_doc_count": 0,             "buckets" : [                 {                    "key" : "male",                    "doc_count" : 10                },                {                    "key" : "female",                    "doc_count" : 10                },            ]        }    }}

数据的不确定性

使用 terms 聚合,结果可能带有一定的偏差与错误性。

举个例子:

我们想要获取 name 字段中出现频率最高的前 5 个。

此时,客户端向 ES 发送聚合请求,主节点接收到请求后,会向每个独立的分片发送该请求。

分片独立的计算自己分片上的前 5 个 name,然后返回。当所有的分片结果都返回后,在主节点进行结果的合并,再求出频率最高的前 5 个,返回给客户端。

这样就会造成一定的误差,比如最后返回的前 5 个中,有一个叫 A 的,有 50 个文档;B 有 49。但是由于每个分片独立的保存信息,信息的分布也是不确定的。有可能第一个分片中 B 的信息有 2 个,但是没有排到前 5,所以没有在最后合并的结果中出现。这就导致B的总数少计算了 2,本来可能排到第一位,却排到了 A 的后面。

size 与 shard_size

为了改善上面的问题,就可以使用 size 和 shard_size 参数。

  • size 参数规定了最后返回的 term 个数(默认是10个)
  • shard_size 参数规定了每个分片上返回的个数
  • 如果 shard_size 小于 size,那么分片也会按照 size 指定的个数计算

通过这两个参数,如果我们想要返回前 5 个,size=5;shard_size 可以设置大于 5,这样每个分片返回的词条信息就会增多,相应的误差几率也会减小。

order 排序

order 指定了最后返回结果的排序方式,默认是按照 doc_count 排序。

{    "aggs" : {        "genders" : {            "terms" : {                "field" : "gender",                "order" : { "_count" : "asc" }            }        }    }}

也可以按照字典方式排序:

{    "aggs" : {        "genders" : {            "terms" : {                "field" : "gender",                "order" : { "_term" : "asc" }            }        }    }}

当然也可以通过 order 指定一个单值的 metric 聚合来排序。

{    "aggs" : {        "genders" : {            "terms" : {                "field" : "gender",                "order" : { "avg_height" : "desc" }            },            "aggs" : {                "avg_height" : { "avg" : { "field" : "height" } }            }        }    }}

同时也支持多值的 metric 聚合,不过要指定使用的多值字段:

{    "aggs" : {        "genders" : {            "terms" : {                "field" : "gender",                "order" : { "height_stats.avg" : "desc" }            },            "aggs" : {                "height_stats" : { "stats" : { "field" : "height" } }            }        }    }}

min_doc_count 与 shard_min_doc_count

聚合的字段可能存在一些频率很低的词条,如果这些词条数目比例很大,那么就会造成很多不必要的计算。

因此可以通过设置 min_doc_count 和 shard_min_doc_count 来规定最小的文档数目,只有满足这个参数要求的个数的词条才会被记录返回。

通过名字就可以看出:

  • min_doc_count:规定了最终结果的筛选
  • shard_min_doc_count:规定了分片中计算返回时的筛选

script

桶聚合也支持脚本的使用:

{    "aggs" : {        "genders" : {            "terms" : {                "script" : "doc['gender'].value"            }        }    }}

以及外部脚本文件:

{    "aggs" : {        "genders" : {            "terms" : {                "script" : {                    "file": "my_script",                    "params": {                        "field": "gender"                    }                }            }        }    }}

filter

filter 字段提供了过滤的功能,使用两种方式:include 可以过滤出包含该值的文档;相反则使用 exclude。

例如:

{    "aggs" : {        "tags" : {            "terms" : {                "field" : "tags",                "include" : ".*sport.*",                "exclude" : "water_.*"            }        }    }}

上面的例子中,最后的结果应该包含 sport 并且不包含 water。

也支持数组的方式,定义包含与排除的信息:

{    "aggs" : {        "JapaneseCars" : {             "terms" : {                 "field" : "make",                 "include" : ["mazda", "honda"]             }         },        "ActiveCarManufacturers" : {             "terms" : {                 "field" : "make",                 "exclude" : ["rover", "jensen"]             }         }    }}

多字段聚合

通常情况,terms 聚合都是仅针对于一个字段的聚合。因为该聚合是需要把词条放入一个哈希表中,如果多个字段就会造成 n^2 的内存消耗。

不过,对于多字段,ES 也提供了下面两种方式:

  • 1 使用脚本合并字段
  • 2 使用 copy_to 方法,合并两个字段,创建出一个新的字段,对新字段执行单个字段的聚合。

collect 模式

对于子聚合的计算,有两种方式:

  • depth_first 直接进行子聚合的计算
  • breadth_first 先计算出当前聚合的结果,针对这个结果在对子聚合进行计算。

默认情况下 ES 会使用深度优先,不过可以手动设置成广度优先,比如:

{    "aggs" : {        "actors" : {             "terms" : {                 "field" : "actors",                 "size" : 10,                 "collect_mode" : "breadth_first"             },            "aggs" : {                "costars" : {                     "terms" : {                         "field" : "actors",                         "size" : 5                     }                 }            }         }    }}

当然,多字段聚合需要写好长一串的查询体,如果字段太多,那岂不是要疯了(当然一般也不会太多,太多的话对性能也有影响)。不过,我们可以自己写个递归函数来构建 aggs 。

# Ruby​# test.rb  def build_aggs_from_fields(fields, aggs_hash)  return if fields.empty?  field = fields.shift  aggs_hash['aggs'] = {    "all_#{field}" => {      'terms' => { field: field, size: 1000 }    }  }  build_aggs_from_fields(fields, aggs_hash['aggs']["all_#{field}"])endfields = ['os', 'os_version', 'job_state']aggs_hash = {}​build_aggs_from_fields(fields, aggs_hash)pp aggs_hash[root@master ruby_learning]# ruby test.rb{"aggs"=>  {"all_os"=>    {"terms"=>{:field=>"os", :size=>1000},     "aggs"=>      {"all_os_version"=>        {"terms"=>{:field=>"os_version", :size=>1000},         "aggs"=>          {"all_job_state"=>{"terms"=>{:field=>"job_state", :size=>1000}}}}}}}}------------------------------------------------------------# Ruby​# test.rb  def build_aggs_from_fields(fields)  aggs_hash = {}  return if fields.empty?  field = fields.shift  aggs_hash['aggs'] ||= {}  aggs_hash['aggs']["all_#{field}"] = {    'terms' => { field: field, size: 1000 }  }  sub_aggs = build_aggs_from_fields(fields)  aggs_hash['aggs']["all_#{field}"].merge!(sub_aggs) if sub_aggs  aggs_hashendfields = ['os', 'os_version', 'job_state']pp build_aggs_from_fields(fields)[root@master ruby_learning]# ruby test.rb {"aggs"=>  {"all_os"=>    {"terms"=>{:field=>"os", :size=>1000},     "aggs"=>      {"all_os_version"=>        {"terms"=>{:field=>"os_version", :size=>1000},         "aggs"=>          {"all_job_state"=>{"terms"=>{:field=>"job_state", :size=>1000}}}}}}}}

缺省值 Missing value

缺省值指定了缺省的字段的处理方式:

{    "aggs" : {        "tags" : {             "terms" : {                 "field" : "tags",                 "missing": "N/A"              }         }    }}

上面的例子都是只有聚合而没有查询,如果你认为 ElasticSearch 的功能也不过如此的话,那你就大错特错了!

带查询的 Terms 聚合

{    "query" : {        "bool" : {            # must: build_multi_field_subquery_body(items)            "must" : [{:term=>{"os"=>"openeuler"}}]        }    },    "aggs" : {        "all_os" : {            "terms" : { field: "os" },            "aggs" : {                "all_state" : {                    "terms" : { "field" : "job_state" },                }            }        }    },    "size" : 0}

 

转载地址:http://lnjqi.baihongyu.com/

你可能感兴趣的文章
趣链 BitXHub跨链平台 (4)跨链网关“初介绍”
查看>>
九度OJ 1091:棋盘游戏 (DP、BFS、DFS、剪枝)
查看>>
Openfiler 配置 NFS 示例
查看>>
Oracle 11.2.0.1 RAC GRID 无法启动 : Oracle High Availability Services startup failed
查看>>
Oracle 18c 单实例安装手册 详细截图版
查看>>
Oracle Linux 6.1 + Oracle 11.2.0.1 RAC + RAW 安装文档
查看>>
Oracle 11g 新特性 -- Online Patching (Hot Patching 热补丁)说明
查看>>
Oracle 11g 新特性 -- ASM 增强 说明
查看>>
Oracle 11g 新特性 -- Database Replay (重演) 说明
查看>>
Oracle 11g 新特性 -- 自动诊断资料档案库(ADR) 说明
查看>>
CSDN博客之星 投票说明
查看>>
Oracle wallet 配置 说明
查看>>
Oracle smon_scn_time 表 说明
查看>>
VBox fdisk 不显示 添加的硬盘 解决方法
查看>>
Java多态性理解
查看>>
【屌丝程序的口才逆袭演讲稿50篇】第一篇:互联网时代U盘化生存方式 【张振华.Jack】
查看>>
CentOS6.4配置Hadoop-2.6.0集群配置安装指南(经过实战演练)【张振华.Jack】
查看>>
【屌丝程序的口才逆袭演讲稿50篇】第二篇:专注的力量 [张振华.Jack]
查看>>
BFS——求矩阵中“块”的个数
查看>>
BFS——走迷宫的最小步数
查看>>