范围(range)聚合

一个基于值源的多桶聚合,使用户能够定义一组范围,每个范围代表一个桶。 在聚合过程中,将根据每个桶的范围检查从每个文档中提取的值,并将相关/匹配的文档“分桶”。 请注意,此聚合包括每个范围的from值,但不包括to值。

示例:

GET /_search
{
    "aggs" : {
        "price_ranges" : {
            "range" : {
                "field" : "price",
                "ranges" : [
                    { "to" : 100.0 },
                    { "from" : 100.0, "to" : 200.0 },
                    { "from" : 200.0 }
                ]
            }
        }
    }
}

响应:

{
    ...
    "aggregations": {
        "price_ranges" : {
            "buckets": [
                {
                    "key": "*-100.0",
                    "to": 100.0,
                    "doc_count": 2
                },
                {
                    "key": "100.0-200.0",
                    "from": 100.0,
                    "to": 200.0,
                    "doc_count": 2
                },
                {
                    "key": "200.0-*",
                    "from": 200.0,
                    "doc_count": 3
                }
            ]
        }
    }
}

keyed 响应

keyed标志设置为true会将唯一的字符串键与每个桶相关联,并将范围作为哈希而不是数组返回:

GET /_search
{
    "aggs" : {
        "price_ranges" : {
            "range" : {
                "field" : "price",
                "keyed" : true,
                "ranges" : [
                    { "to" : 100 },
                    { "from" : 100, "to" : 200 },
                    { "from" : 200 }
                ]
            }
        }
    }
}

响应:

{
    ...
    "aggregations": {
        "price_ranges" : {
            "buckets": {
                "*-100.0": {
                    "to": 100.0,
                    "doc_count": 2
                },
                "100.0-200.0": {
                    "from": 100.0,
                    "to": 200.0,
                    "doc_count": 2
                },
                "200.0-*": {
                    "from": 200.0,
                    "doc_count": 3
                }
            }
        }
    }
}

也可以为每个范围自定义一个键:

GET /_search
{
    "aggs" : {
        "price_ranges" : {
            "range" : {
                "field" : "price",
                "keyed" : true,
                "ranges" : [
                    { "key" : "cheap", "to" : 100 },
                    { "key" : "average", "from" : 100, "to" : 200 },
                    { "key" : "expensive", "from" : 200 }
                ]
            }
        }
    }
}

响应:

{
    ...
    "aggregations": {
        "price_ranges" : {
            "buckets": {
                "cheap": {
                    "to": 100.0,
                    "doc_count": 2
                },
                "average": {
                    "from": 100.0,
                    "to": 200.0,
                    "doc_count": 2
                },
                "expensive": {
                    "from": 200.0,
                    "doc_count": 3
                }
            }
        }
    }
}

脚本

range 聚合接受script参数。 此参数允许定义一个内联的(inline)脚本(script),它将在聚合执行期间被执行。

下面这个示例显示了如何使用无痛(painless)脚本语言和无脚本参数的内联(inline)脚本:

GET /_search
{
    "aggs" : {
        "price_ranges" : {
            "range" : {
                "script" : {
                    "lang": "painless",
                    "source": "doc['price'].value"
                },
                "ranges" : [
                    { "to" : 100 },
                    { "from" : 100, "to" : 200 },
                    { "from" : 200 }
                ]
            }
        }
    }
}

也可以使用存储(的)脚本。下面是一个简单的使用存储脚本的示例:

POST /_scripts/convert_currency
{
  "script": {
    "lang": "painless",
    "source": "doc[params.field].value * params.conversion_rate"
  }
}

这个新的存储脚本可以用于 range 聚合,如下所示:

GET /_search
{
    "aggs" : {
        "price_ranges" : {
            "range" : {
                "script" : {
                    "id": "convert_currency", 
                    "params": { 
                        "field": "price",
                        "conversion_rate": 0.835526591
                    }
                },
                "ranges" : [
                    { "from" : 0, "to" : 100 },
                    { "from" : 100 }
                ]
            }
        }
    }
}

存储脚本的id

执行存储脚本时使用的参数

值脚本(value script)

假设产品价格以美元(USD)计算,但我们希望得到以欧元(EURO)计算的价格范围。 我们可以使用值脚本在聚合之前转换价格(假设转换率为0.8)。

GET /sales/_search
{
    "aggs" : {
        "price_ranges" : {
            "range" : {
                "field" : "price",
                "script" : {
                    "source": "_value * params.conversion_rate",
                    "params" : {
                        "conversion_rate" : 0.8
                    }
                },
                "ranges" : [
                    { "to" : 35 },
                    { "from" : 35, "to" : 70 },
                    { "from" : 70 }
                ]
            }
        }
    }
}

子聚合

下面这个例子不仅将文档“分桶”到不同的桶中,还计算每个价格范围内的价格统计数据。

GET /_search
{
    "aggs" : {
        "price_ranges" : {
            "range" : {
                "field" : "price",
                "ranges" : [
                    { "to" : 100 },
                    { "from" : 100, "to" : 200 },
                    { "from" : 200 }
                ]
            },
            "aggs" : {
                "price_stats" : {
                    "stats" : { "field" : "price" }
                }
            }
        }
    }
}

响应:

{
  ...
  "aggregations": {
    "price_ranges": {
      "buckets": [
        {
          "key": "*-100.0",
          "to": 100.0,
          "doc_count": 2,
          "price_stats": {
            "count": 2,
            "min": 10.0,
            "max": 50.0,
            "avg": 30.0,
            "sum": 60.0
          }
        },
        {
          "key": "100.0-200.0",
          "from": 100.0,
          "to": 200.0,
          "doc_count": 2,
          "price_stats": {
            "count": 2,
            "min": 150.0,
            "max": 175.0,
            "avg": 162.5,
            "sum": 325.0
          }
        },
        {
          "key": "200.0-*",
          "from": 200.0,
          "doc_count": 3,
          "price_stats": {
            "count": 3,
            "min": 200.0,
            "max": 200.0,
            "avg": 200.0,
            "sum": 600.0
          }
        }
      ]
    }
  }
}

如果子聚合也基于与 range 聚合相同的值源(如上面示例中的stats聚合),则可以省略其值源的定义。 下面这个例子将返回与上面相同的响应:

GET /_search
{
    "aggs" : {
        "price_ranges" : {
            "range" : {
                "field" : "price",
                "ranges" : [
                    { "to" : 100 },
                    { "from" : 100, "to" : 200 },
                    { "from" : 200 }
                ]
            },
            "aggs" : {
                "price_stats" : {
                    "stats" : {} 
                }
            }
        }
    }
}

不需要指定 field 为price,因为默认情况下,会从父级的 range 聚合中“继承”