Elasticsearch 基础教程

Elasticsearch 高级教程

Elasticsearch 插件

Elasticsearch 笔记

Elasticsearch FAQ

original icon
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.knowledgedict.com/tutorial/elasticsearch-aggregations-terms-aggs.html

elasticsearch(es) terms 聚合(aggregation)查询详解

Elasticsearch(Es)聚合查询(指标聚合、桶聚合) Elasticsearch(Es)聚合查询(指标聚合、桶聚合)


基于 elasticsearch 构建的业务中最常用的聚合查询就是 terms aggregation,它基于 term 粒度的词或数字值进行聚合,如果聚合字段类型是 text,会对一个一个的词根进行聚合,通常不会在 text 类型的字段上使用聚合,terms 聚合类似关系数据库中的 group by 查询。

GET product/_search
{
  "track_total_hits": true,
  "size": 0,
  "aggregations": {
    "store_id_agg_udf_name": {
      "terms": {
        "field": "store_id",
        "size": 5
      }
    }
  }
}

假设有商品索引 product,根据商品的商家门店 store_id 字段聚合查询 5 条记录如上。若只返回聚合的结果,非每个记录的 source 内容,size 指定 0,如上。返回结果如下:

{
  "took" : 11,
  "timed_out" : false,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 160955,
      "relation" : "gte"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "store_id_agg_udf_name" : {
      "doc_count_error_upper_bound" : 257,
      "sum_other_doc_count" : 156356,
      "buckets" : [
        {
          "key" : 148272,
          "doc_count" : 3038
        },
        {
          "key" : 4669,
          "doc_count" : 453
        },
        {
          "key" : 661,
          "doc_count" : 378
        },
        {
          "key" : 24688,
          "doc_count" : 366
        },
        {
          "key" : 20296,
          "doc_count" : 364
        }
      ]
    }
  }
}

语法

terms 聚合的语法结构如下,核心关键字是 terms

{
  "aggs": {  // 等同 aggregations
    "profit_terms": {  // 自定义的聚合名称
      "terms": { // terms 聚合 关键字
        "field": "index_field_name",  //  索引中要聚合的字段名 
        "size": 30,  //  获取的聚合字段个数
        "shard_size": 100,  //  分片获取的聚合字段个数
        "min_doc_count": 1,  //  各个分片聚合后的最小聚合数
        "shard_min_doc_count": 0  //  每个分片聚合的最小聚合数
      }
    }
  }
}

terms aggs 支持很多参数,以及子聚合等高级用法,参照下面的参数讲解。

参数

size

默认情况下,terms 聚合查询返回对应文档数最多的前 10 个聚合结果,我们可以通过 size 来调整返回的聚合结果数,最大值受到 search.max_buckets 配置参数的限制。

如果只包含不到 1000 左右不同的唯一 term 时,我们可以通过增加 size 值来返回所有的数据;若有更多的不同 term 值时,可以改用 composite aggregation(这个复合聚合代价大,可以用在离线计算上而非在线实时服务上)。

size 值越大使用更多的内存进行计算,并将整个聚合推向接近极限,所以针对 size 值的调整要与实际需求相结合权衡考虑。

shard_size

shard_size 顾名思义是针对每个分片的获取文档的条数,我们知道 es 是分布式的系统,数据在物理层面分不同节点,在逻辑层面也会分片,为了获得更准确的结果,agg 从每个分片中获取的 top size 数要比实际要获取的 size 大,默认情况下 shard_size = size * 1.5 + 10

此外,shard_size 的设置不能小于 size,因为这样没有意义,elasticsearch 针对这种情况,会把 shard_size 纠正为 size 大小。

从上面 size 和 shard_size 的参数定义可以看出,es 的 terms 聚合查询的数据就有不确定性,结果可能和实际结果有一定的偏差与错误性。

es 的聚合查询其实是 map-reduce 的过程,由于 elasticsearch 存在分片的情况,即文档分布不可控,每个分片的聚合统计后的 top 获取后再 reduce 有可能和真实的结果有出入,所以我们要提高 shard_size 数来让其更接近真实值;但同时也要考虑 shard_size 的增大也会带来相应的代价,需要按需设置。

min_doc_count

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

min_doc_count 指定各个分片聚合后,再筛选的文档聚合个数最小值,默认为 1。

shard_min_doc_count

shard_min_doc_count 指定每个分片筛选的文档个数最小值,默认为 0。

collect_mode

collect_mode 参数指定聚合收集(collect)数据时的模式,支持 breadth_first 和 depth_first 两种,即广度优先深度优先

execution_hint

执行提示,类似于 MySQL 数据库的 hint 功能。

Term Aggregation 聚合通常基于如下两种实现方式:

  1. 通过直接使用字段值来聚合每个桶的数据(map);
    只有当很少的文档匹配查询时,才应该考虑映射。否则,基于序号的执行模式会快得多。默认情况下,map 只在脚本上运行聚合时使用,因为它们没有序号。
  2. 通过使用字段的全局序号并为每个全局序号分配一个 bucket(global_ordinals);
    keyword 类型的字段默认使用 global_ordinals 机制,它使用全局序号动态分配 bucket,因此内存使用与属于聚合范围的文档的值的数量是线性的。

默认情况下,ES 会自动选择,但也可以通过参数 execution_hint 进行人工干预,可选值:global_ordinalsmap

missing

missing 参数定义应如何处理聚合字段缺省值的文档,默认情况下,缺省值的文档将被忽略,但它们也可以指定为具体值。

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

上述示例中,tags 字段值不存在的文档,作为 N/A 值的桶进行统计。

在多个索引上进行聚合操作时,聚合字段的类型可能在所有索引中都不相同。某些类型彼此兼容(如 integer 和 long 或 float 和 double),但当类型是十进制数和非十进制数的混合时,terms 聚合会将非十进制数提升为十进制数。这可能会导致桶值的精度损失。

order 参数

terms 聚合通过 order 参数指定聚合的排序方式,若指定多个,会按照指定顺序依次排序,默认情况下,按照聚合文档数 _count 降序返回。

排序方式一种时,用大括号的对象方式书写;多个时,用中括号开头的数组方式定义。

按照 term 值排序

terms 聚合查询中 _key 关键字表示要聚合 term 的具体值,如根据关键字或数字的升序或降序排列返回。升序示例如下:

GET post/_search
{
  "aggs": {
    "tags_agg": {
      "terms": {
        "field": "tags",
        "order": { 
          "_key": "asc" 
        }
      }
    }
  }
}

若降序,将上述示例中的 asc 改为 desc 即可。

按照聚合文档数排序

terms 聚合查询处理提供 _key 的关键字,还提供了 _count,它表示 term 对应的文档数,类似于关系型数据库中 group by 聚合语句中 count 函数返回的值。

GET product/_search
{
  "aggs": {
    "store_id_agg": {
      "terms": {
        "field": "store_id",
        "order": { 
          "_count": "desc" 
        }
      }
    }
  }
}

按照子聚合(sub aggregation)统计排序

子聚合(sub aggregation)是聚合内部嵌套的聚合,可以用内置的 maxminavgsum 等聚合方法,也可以通过脚本(script)的统计。

子聚合同样也因为基于 shard 的聚合,所以也有一定的不准确性。

子聚合只有在两种情况下是准确的,只按照一个字段的最大值或最小值

GET product/_search
{
  "from": 0,
  "size": 0,
  "track_total_hits": true,
  "aggregations": {
    "store_id_agg": {
      "terms": {
        "field": "store_id",
        "size": 200,
        "shard_size": 500,
        "min_doc_count": 1,
        "shard_min_doc_count": 0,
        "show_term_doc_count_error": true,
        "execution_hint": "map",
        "order": [
          {
            "order_score": "desc"
          },
          {
            "star_score": "desc"
          }
        ],
        "collect_mode": "breadth_first"
      },
      "aggregations": {
        "star_score": {
          "max": {
            "field": "star_score"
          }
        },
        "order_score": {
          "sum": {
            "script": {
              "source": "(doc['star_score'].value/5.0+doc['bid'].value/5.0+1.0)*doc['sold_cnt'].value"
            }
          }
        }
      }
    }
  }
}

如上示例,先通过脚本的分数取累积和之后降序,star_score 表示门店的5星评分,由于同一个门店的五星评分值是相同的,可以如上形式,当第一个排序分相同时,会查看第二个排序项,但这个已经存在不准确性了,需要根据业务特点选择使用。

 

Elasticsearch 的聚合功能十分强大,可在数据上做复杂的分析统计。它提供的聚合分析功能有指标聚合(metrics aggregat ...
es bool 查询是把任意多个简单查询组合在一起,使用 must、should、must_not、filter 选项来表示简单查询之间的逻 ...
Elasticsearch 查询语句采用基于 RESTful 风格的接口封装成 JSON 格式的对象,称之为 Query DSL。Elast ...
Elasticsearch索引的配置项主要分为静态配置属性和动态配置属性,静态配置属性是索引创建后不能修改,而动态配置属性则可以随时修改。r ...
elasticsearch 删除索引操作能够用单个命令来进行完成,有不同的操作形式,具体如下: ...