本地英文版地址: ../en/search-aggregations-bucket-histogram-aggregation.html
直方图(histogram)聚合edit
一个基于值源(value source)的多桶聚合,可应用于从文档中提取的数值或数值范围值。
它根据值动态构建固定大小(也称为间隔/interval)的桶。
例如,如果文档有一个保存价格price
(数字)的字段,我们可以配置这个聚合来动态构建间隔为5
的桶(本例中是价格,则它可以表示5元)。
执行聚合时,将计算每个文档的 price 字段,并将其向下舍入到最接近的桶——例如,如果价格是32
,桶大小是5
,则舍入将得到30
,因此该文档将“落入”与键30
相关联的桶。
为了更正式,这里使用了舍入函数:
bucket_key = Math.floor((value - offset) / interval) * interval + offset
对于范围值,一个文档可能会落入多个桶。 第一个桶从范围的下限开始计算,计算方式与计算单个值的桶相同。 最后一个桶以相同的方式从范围的上限开始计算,范围计入这两个桶之间(含)的所有桶。
interval
必须是正的小数,而offset
必须是[0, interval)
中的数(大于或等于0
且小于interval
的小数)
下面的代码片段根据price
以50
为间隔对产品进行“分桶”:
POST /sales/_search?size=0 { "aggs" : { "prices" : { "histogram" : { "field" : "price", "interval" : 50 } } } }
响应可能如下所示:
{ ... "aggregations": { "prices" : { "buckets": [ { "key": 0.0, "doc_count": 1 }, { "key": 50.0, "doc_count": 1 }, { "key": 100.0, "doc_count": 0 }, { "key": 150.0, "doc_count": 2 }, { "key": 200.0, "doc_count": 3 } ] } } }
上面的响应显示没有文档的 price 在[100, 150)
范围内。
默认情况下,响应将用空桶填充直方图中的间隙。
得益于min_doc_count
设置,可以更改和请求具有更高最小数量的桶:
POST /sales/_search?size=0 { "aggs" : { "prices" : { "histogram" : { "field" : "price", "interval" : 50, "min_doc_count" : 1 } } } }
响应:
{ ... "aggregations": { "prices" : { "buckets": [ { "key": 0.0, "doc_count": 1 }, { "key": 50.0, "doc_count": 1 }, { "key": 150.0, "doc_count": 2 }, { "key": 200.0, "doc_count": 3 } ] } } }
默认情况下,histogram
返回数据本身范围内的所有桶,也就是说,具有最小值的文档(使用直方图)将确定最小桶(具有最小键的桶),具有最大值的文档将确定最大桶(具有最大键的桶)。
通常,当请求空桶时,这会导致混乱,特别是当数据也被过滤时。
为了理解其中的原因,我们来看一个例子:
假设你正在过滤你的请求,以获取值在0
到500
之间的所有文档,此外,你希望使用间隔为50
的直方图来分割每个价格的数据。
你还指定了"min_doc_count" : 0
,因为你希望获得所有的桶,即使是空的桶。
如果碰巧所有产品(文档)的价格都高于 100
,那么你将得到的第一个桶将是以100
为键的桶。
这是令人困惑的,因为很多时候,你也想得到0 - 100
之间的那些桶。
通过extended_bounds
设置,你现在可以“强制” histogram 聚合开始根据特定的min
值构建桶,并继续构建桶直到max
值(即使不再有文档)。
仅当min_doc_count
为 0 时,使用extended_bounds
才有意义(如果min_doc_count
大于0,则永远不会返回空桶)。
注意(顾名思义), extended_bounds
不是过滤桶。
也就是说,如果extended_bounds.min
高于从文档中提取的值,文档仍将指示第一个桶将是什么(extended_bounds.max
和最后一个桶也是如此)。
对于过滤桶,应该使用适当的from
/to
设置将 histogram 聚合嵌套在范围filter
聚合下。
示例:
POST /sales/_search?size=0 { "query" : { "constant_score" : { "filter": { "range" : { "price" : { "to" : "500" } } } } }, "aggs" : { "prices" : { "histogram" : { "field" : "price", "interval" : 50, "extended_bounds" : { "min" : 0, "max" : 500 } } } } }
聚合范围时,桶基于返回的文档的值。 这意味着响应可能包含查询范围之外的桶。 例如,如果查询是要查找大于100的值,并且范围从50到150,interval为50,那么该文档将位于3个桶中——50、100和150。 一般来说,最好将查询和聚合步骤看作是独立的——查询负责选择一组文档,然后聚合对这些文档进行分桶,而不考虑它们是如何被选择的。 更多信息和示例参考 有关范围字段分桶的提示。
默认情况下,返回的桶按它们的key
升序排序,尽管可以使用order
设置来控制排序行为。
支持与terms 聚合
相同的order
功能。
默认情况下,桶的键从0开始,然后以interval
的均匀步长继续,例如,如果 interval 是10
,前三个桶(假设其中有数据)将是[0, 10)
、[10, 20)
、[20, 30)
。
可以通过使用offset
选项来移动桶的边界。
这可以用一个例子来说明。
如果有10个值在5到14之间的文档,使用间隔10
将产生两个桶,每个桶有5个文档。
如果使用额外的5
5,将只有一个包含所有10个文档的桶[5, 15)
。
默认情况下,桶作为有序数组返回。 也可以请求以哈希形式的响应,而不是以桶的键作为键:
POST /sales/_search?size=0 { "aggs" : { "prices" : { "histogram" : { "field" : "price", "interval" : 50, "keyed" : true } } } }
响应:
{ ... "aggregations": { "prices": { "buckets": { "0.0": { "key": 0.0, "doc_count": 1 }, "50.0": { "key": 50.0, "doc_count": 1 }, "100.0": { "key": 100.0, "doc_count": 0 }, "150.0": { "key": 150.0, "doc_count": 2 }, "200.0": { "key": 200.0, "doc_count": 3 } } } } }