本地英文版地址: ../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
}
}
}
}
}