一个基于multi-bucket值的聚合,其中bucket是动态构建的-每个唯一值一个桶
Example:
{
"aggs" : {
"genres" : {
"terms" : { "field" : "genre" }
}
}
}
Response:
{
...
"aggregations" : {
"genres" : {
"doc_count_error_upper_bound": 0, (1)
"sum_other_doc_count": 0, (2)
"buckets" : [ (3)
{
"key" : "jazz",
"doc_count" : 10
},
{
"key" : "rock",
"doc_count" : 10
},
{
"key" : "electronic",
"doc_count" : 10
},
]
}
}
}
(1) 文档上的错误的上限对每一个term都有影响.看下面
(2) 当有很多的唯一term时,elasticsearch只会返回前几个term(默认是10),这个数字是没有响应部分的全部桶的文档计数总和.
(3) top buckets的列表,top顺序是由order定义的.
默认情况下,terms aggregation将会返回通过doc_count降序排列后的前十个term的桶.可以通过设置size参数大小来改变这种默认行为.
可以设置size参数来定义从全部的terms list中返回多少个term bucket.默认情况下,协调搜索过程的节点将请求每一个分片使其提供自己的top size term buckets.一旦所有的分片相应,协调节点将会对每个shard的结果合并重新排序,取top size term buckets.然后返回给客户端.这就意味着如果term buckets的数量大于size参数,返回的列表是不准确的(可能是term计数有点偏差,甚至可能是本应该在top size term buckets中的但没有返回).
warning : Deprecated in 2.4.0
size设置为0,则会默认将size设置为integer.MAX_VALUE,已经废弃.并且将会在下一个主要的版本中移除.
综上所述,terms agg的文档计数(以及任何子聚合的结果)不总是准确的.这是因为每一个分片提供自己的视图来显示terms有哪些,然后将它们合并起来给出最终的视图.考虑以下场景:
请求获取字段product中的前5个term,按照三个分片的文档计数排序,要求每个shard给出它的前5个term.
{
"aggs" : {
"products" : {
"terms" : {
"field" : "product",
"size" : 5
}
}
}
}
三个shard的term如下:
- | shard A | shard B | shard C |
---|---|---|---|
1 | Product A (25) | Product A (30) | Product A (45) |
2 | Product B (18) | Product B (25) | Product C (44) |
3 | Product C (6) | Product F (17) | Product Z (36) |
4 | Product D (3) | Product Z (16) | Product G (30) |
5 | Product E (2) | Product G (15) | Product E (29) |
6 | Product F (2) | Product H (14) | Product H (28) |
7 | Product G (2) | Product I (10) | Product Q (2) |
8 | Product H (2) | Product Q (6) | Product D (1) |
9 | Product I (1) | Product J (8) | |
10 | Product J (1) | Product C (4) |
shard返回前5个term,所以每个shard的结果为:
- | shard A | shard B | shard C |
---|---|---|---|
1 | Product A (25) | Product A (30) | Product A (45) |
2 | Product B (18) | Product B (25) | Product C (44) |
3 | Product C (6) | Product F (17) | Product Z (36) |
4 | Product D (3) | Product Z (16) | Product G (30) |
5 | Product E (2) | Product G (15) | Product E (29) |
从每个shard中选取前5个term,并将它们组合成最后的前5个term,得到一下结果:
- | final result |
---|---|
1 | Product A (100) |
2 | Product Z (52) |
3 | Product C (50) |
4 | Product G (45) |
5 | Product B (43) |
因为Product A是从所有分片中返回的,所以它的计数是准确的.Product C 只有 shard A 和 C 返回,所以它的计数是50,但不是准确的计数.Product C存在于shard B中,但其计数4排名不够高,无法将Product C放入该shard的前5个term中.Product Z 也只返回2个shard,但是第三个shard中不包含该term.没有办法知道文档中有一个错误计数Product C而不是Product Z.Product H的计数44在三个shard中,但没有在最终的名单上,因为它没有进入每个shard的前五.
请求的大小越高(size越大),结果更准确,但同时,计算最终的结果成本越高(一方面在shard级别上管理的优先级队列更大,另一方面是节点和客户机之间的数据传输更大).
shard_size参数可以控制每个shard的优先级队列大小,一旦所有的shard响应,协调节点将减少它们的最终结果基于size参数,这种方式,可以增加返回条件的准确性,避免了a big list of buckets返回给客户端.
note: shard_size的值小于size是没有意义的.如果这样设置了,elasticsearch会重置shard_size的值为size的值大小.
默认shard_size的值是size参数的倍数.这依赖于分片的数量.
有两个错误在terms agg中显示,第一个给出了聚合作为一个整体的值,它代表了一个term的最大潜在文档数,但这个term最终没有出现在最终的term列表中.这个是计算每个shard返回的最后一项的文档计数总和.对于上面给出的例子,该值将是46(2+15+29).这意味着最坏的情况是,没有返回的term可以拥有第4高的文档计数.
{
...
"aggregations" : {
"products" : {
"doc_count_error_upper_bound" : 46,
"buckets" : [
{
"key" : "Product A",
"doc_count" : 100
},
{
"key" : "Product Z",
"doc_count" : 52
},
...
]
}
}
}
第二个错误值可以通过将show_term_doc_count_error设置为true来启用.这显示了聚合返回的每个term的错误值,该值表示term的文档计数的最坏情况,可以通过此值来决定shard_size的参数是否针对该term有用.计算方法是将所有没有返回该term的shard返回的最后一个term计数相加.在上面的例子中,Product C的文档计数中的错误值将是15,因为Shard B是唯一一个不返回该term的shard,而最后的一个term的计数是15.Product C实际的文档计数是54,而没有在最终列表中的Product C的文档计数是4,最坏的情况是15.Product A 的文档计数的错误值为0,因为每个shard都返回它,所以它的文档计数是准确的.
{
...
"aggregations" : {
"products" : {
"doc_count_error_upper_bound" : 46,
"buckets" : [
{
"key" : "Product A",
"doc_count" : 100,
"doc_count_error_upper_bound" : 0
},
{
"key" : "Product Z",
"doc_count" : 52,
"doc_count_error_upper_bound" : 2
},
...
]
}
}
}
这些错误值只能在doc_count降序排列的情况下计算,当聚合按照term本身(升序或降序)排序时,文档计数中没有错误.这是因为一个term在一个shard中返回而在另一个shard中没有返回,那么该term要么不会出现在最终列表中,要么该shard中的不包含该term.当聚合按子聚合或按升序文档计数排序时,无法确定文档计数中的错误,并给出一个值-1来表示这一点.
可以通过设置order参数来指定桶的顺序.默认情况下,这些bucket是由它们的doc_count降序排列的.可以改变如下所示的行为:
通过升序_count或子聚合排序是不允许的,因为这会增加文档计数的错误.查询一个shard是可以的,或当被聚合的字段在索引时用作路由键时,在这种情况下结果是准确的,因为shard不具有相交的term.否则,错误将是无限大的.一个仍然有用的特殊情况是通过min agg和max agg排序.计数不是准确的,但至少最上面的桶将被正确的挑选.
按照doc_count升序方式排序桶
{
"aggs" : {
"genres" : {
"terms" : {
"field" : "genre",
"order" : { "_count" : "asc" }
}
}
}
}
按照term的字母顺序升序排序桶
{
"aggs" : {
"genres" : {
"terms" : {
"field" : "genre",
"order" : { "_term" : "asc" }
}
}
}
}
通过单值度量子聚合(通过聚合名称标识)排序桶
{
"aggs" : {
"genres" : {
"terms" : {
"field" : "genre",
"order" : { "avg_play_count" : "desc" }
},
"aggs" : {
"avg_play_count" : { "avg" : { "field" : "play_count" } }
}
}
}
}
通过多值度量子聚合(通过聚合名称标识)排序桶
{
"aggs" : {
"genres" : {
"terms" : {
"field" : "genre",
"order" : { "playback_stats.avg" : "desc" }
},
"aggs" : {
"playback_stats" : { "stats" : { "field" : "play_count" } }
}
}
}
}
warning: pipeline agg 不能用于排序
在其他聚合完成后,pipeline agg将在reduce阶段运行.由于这个原因,它不能用于排序.
还可以根据层次结构中的”更深层次”聚合来排序bucket,只要agg path是single-bucket类型,就支持这种排序.路径中的最后一个聚合可以是single-bucket聚合也可以是度量聚合.如果是single-bucket聚合,顺序将由doc_count来定义.如果是度量聚合,则使用和上面相同的规则(在多值度量聚合的情况下,路径必须指定要排序的度量名称,而在单值度量聚合的情况下,排序将应用该值)
路径必须以以下形式定义:
AGG_SEPARATOR = '>' ;
METRIC_SEPARATOR = '.' ;
AGG_NAME = <the name of the aggregation> ;
METRIC = <the name of the metric (in case of multi-value metrics aggregation)> ;
PATH = [ , ]* [ , ] ;
{
"aggs" : {
"countries" : {
"terms" : {
"field" : "artist.country",
"order" : { "rock>playback_stats.avg" : "desc" }
},
"aggs" : {
"rock" : {
"filter" : { "term" : { "genre" : "rock" }},
"aggs" : { "playback_stats" : { "stats" : { "field" : "play_count" }} } }
}
}
}
}
上面根据摇滚歌曲的平均播放次数对artist.country进行降序排列.
可以使用多个标准来排序桶,方法是提供一系列的顺序标准,如下
{
"aggs" : {
"countries" : {
"terms" : {
"field" : "artist.country",
"order" : [ { "rock>playback_stats.avg" : "desc" }, { "_count" : "desc" } ]
},
"aggs" : {
"rock" : {
"filter" : { "term" : { "genre" : { "rock" }}},
"aggs" : {
"playback_stats" : { "stats" : { "field" : "play_count" }}
}
}
}
}
}
}
上面将根据摇滚歌曲的平均播放次数以及atrist.country的doc_count(降序排列)对artist.country进行排序.
waring : 如果两个桶的排序值是相同的,则按照桶的term字母顺序升序排列,防止桶的不确定性排序.
可以通过min_doc_count设置文档数目最小匹配项.
{
"aggs" : {
"tags" : {
"terms" : {
"field" : "tags",
"min_doc_count": 10
}
}
}
}
上述聚合只返回文档计数>=10的term.默认值为1.
term在shard级别上被收集和排序,然后合并其他shard中收集的term.但是,shard中没有全局文档计数的信息.是否将一个term添加到候选列表取决于使用本地shard频率该term在shard上的计算顺序.min_doc_count只有在合并完所有shard的本地term统计信息后才使用.在某种程度上,决定将该term添加为候选者,而不是非常确定该term是否实际达到所需的min_doc_count.如果低频率term填充候选列表,这可能导致结果中缺少许多(全局)高频率term.为避免这种情况,可以增加shard_size参数以允许分片上有更多的候选term,但是,这会增加内存消耗和网络流量.
shard_min_doc_count 参数
参数shard_min_doc_count调整了切分shard的确定性,如果该term实际上应该被添加到候选列表中,或者不应该被添加到min_doc_count中.只有当该term在本地shard频率高于shard_min_cod_count时才会被考虑.如果你的字典中包含了许多低频词并且你不感兴趣.(例如拼写错误),可以设置shard_min_doc_count参数过滤term,即使合并本地计算,过滤的term也不会达到所需的min_doc_count.shard_min_doc_count每个默认值设置为0,除非显式的设置,否则它没有任何效果.
note: 设置min_doc_count=0也会为没有匹配的命中term返回bucket.但是,一些返回文档计数为0的term可能只属于被删除的文档或者来自其他类型的文档,因此不保证match_all查询会发现这些term的文档计数为正数
-
warning: 当不对doc_count降序排列时,min_doc_count的高值可能会返回一些桶,但这些桶的大小小于size,因为从shard中收集的数据不足导致的.可以通过增加shard_size恢复丢失的bucket.设置shard_min_doc_count过高将导致在shard级别上过滤term.这个值应该设置得比min_doc_count低得多.
使用脚本生成terms:
{
"aggs" : {
"genres" : {
"terms" : {
"script" : "doc['genre'].value"
}
}
}
}
这把script参数解释为使用默认脚本语言而没有脚本参数的inline脚本.要使用file script,使用以下语法:
{
"aggs" : {
"genres" : {
"terms" : {
"script" : {
"file": "my_script",
"params": { "field": "genre" } }
}
}
}
}
tip: 对于索引脚本,用id代替file.
{
"aggs" : {
"genres" : {
"terms" : {
"field" : "genre",
"script" : "'Genre: ' +_value"
}
}
}
}
可以对将要创建的bucket的值进行筛选。这可以使用include和exclude参数来完成,这些参数基于正则表达式字符串或精确值数组。
{
"aggs" : {
"tags" : {
"terms" : {
"field" : "tags",
"include" : ".*sport.*",
"exclude" : "water_.*"
}
}
}
}
在上面的例子中,除了以water_开头的标签(因此不会聚合标记water_sports)之外,所有包含sport这个单词的标签都将创建bucket。include正则表达式将确定“允许”聚合哪些值,而exclude将确定不应该聚合的值。当两个都被定义时,exclude有优先级,也就是说,首先计算include,然后才计算exclude。
为了基于精确的值进行匹配,include和exclude参数可以简单地使用字符串数组来表示在索引中找到的term:
{
"aggs" : {
"JapaneseCars" : {
"terms" : {
"field" : "make",
"include" : ["mazda", "honda"]
}
},
"ActiveCarManufacturers" : {
"terms" : {
"field" : "make",
"exclude" : ["rover", "jensen"]
}
}
}
}
terms 聚合不支持从同一文档中的多个字段收集term.原因是terms agg本身不收集字符串term.而是使用全局序号生成字段中所有唯一值的列表.全局序号会带来重要的性能提升,而在多个字段之间是不可能实现的.
有两种方法可用于跨多个字段执行terms agg:
脚本
使用脚本从多个字段检索term。这将禁用全局序号优化,并且比从单个字段中收集term要慢,但是它提供了在搜索时实现此选项的灵活性。
copy_to field
如果事先知道要从两个或多个字段收集term,那么在映射中使用copy_to在索引时创建一个新的专用字段,该字段包含两个字段的值。您可以在这个单一字段上进行聚合,这将从全局序号优化中获益。
缺失的参数定义了如何处理缺失值的文档。默认情况下,它们将被忽略,但也可以将它们视为有值。
{
"aggs" : {
"tags" : {
"terms" : {
"field" : "tags",
"missing": "N/A" (1)
}
}
}
}
(1) 在tags字段中没有值的文档将与值为N/ a的文档归入同一类别。
官网:https://www.elastic.co/guide/en/elasticsearch/reference/2.4/search-aggregations-bucket-terms-aggregation.html#search-aggregations-bucket-terms-aggregation-script