Skip to main content

直方图 histogram

Histogram Aggregation

直方图聚合是一个用于评估数值型或是数值范围型价值的文档的多桶(multi-bucket)聚合,它可以对参与聚合的值动态生成固定尺寸的桶。

比如,如果一些文档具有数值型字段“price”,我们可以配置聚合间隔为5(在价钱中可能为5元)来动态生成直方图统计。当聚合执行的时候,每个文档的price字段会参与估算,并且为四舍五入到最近的桶中。比如,如果一个文档的price字段值为32,桶的尺寸为5,并且字段值四舍五入后的值为30,那么这个文档就会归入跟30这个关键字关联的桶内。下面的算式可以精确的确定每个文档的归属桶(根据桶的关键字确定)。

bucket_key = Math.floor((value - offset) / interval) * interval + offset

注意:interval必须是是一个十进制的正数,同时offset必须是[0,interval)(一个大于等于0、小于interval的十进制数)之间的一个十进制的数。

以下代码片段根据产品的价格以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
}
]
}
}
}

最小文档数

上面的响应表明,没有文档的价格在[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
}
]
}
}
}

默认情况下,直方图返回数据本身范围内的所有存储桶,即具有最小值的文档(使用直方图)将确定最小存储桶(具有最小关键字的存储桶),而具有最大值的文档将确定最大存储桶(具有最高关键字的存储)。通常,当请求空桶时,这会导致混乱,特别是当数据也被过滤时。

要了解原因,我们来看一个示例:

假设您正在过滤请求以获取值介于0和500之间的所有文档,此外,您还希望使用间隔为50的直方图对每个价格的数据进行切片。您还指定“min_doc_count”:0,因为您希望获取所有桶,即使是空桶。如果所有产品(文档)的价格都高于100,那么您将得到的第一个桶将是以100为关键字的桶。这很令人困惑,因为很多时候,你也希望这些桶在0到100之间。

通过extended_bounds设置,您现在可以“强制”直方图聚合以特定的最小值开始构建桶,并继续构建最大值的桶(即使不再有文档)。只有当min_doc_count为0时,使用extended_bounds才有意义(如果min_doc-count大于0,则不会返回空桶)。

注意 extended_bounds不是过滤桶。意思是如果扩展边界,min大于从文档中提取的值,文档仍将决定第一个bucket是什么(extendedbounds.max和最后一个bucket也是如此)。对于过滤桶,应该使用适当的从/到设置将直方图聚合嵌套在范围过滤器聚合下。

例子:

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
}
}
}
}
}

Order

默认情况下,返回的桶按关键字升序排序,但可以使用order控制顺序。

Offset

默认情况下,存储桶键以0开始,然后以偶数间隔步长继续,例如,如果间隔为10,则前三个存储桶(假设其中有数据)将为[0,10),[10,20),[20,30)。可以使用offset移动存储桶边界。

这可以用一个例子来最好地说明。如果有10个文档的值在5到14之间,则使用间隔10将生成两个桶,每个桶包含5个文档。如果使用额外的偏移量5,则只有一个包含所有10个文档的存储桶[5,15)。

Response Format

默认情况下,存储桶作为有序数组返回。也可以将响应请求为散列,而不是由桶键键入:

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
}
}
}
}
}

Missing value

POST /sales/_search?size=0
{
"aggs" : {
"quantity" : {
"histogram" : {
"field" : "quantity",
"interval": 10,
"missing": 0
}
}
}
}

quantity字段中没有值的文档将与值为0的文档属于同一个存储桶。