日期范围聚合

编辑

一种专门用于日期值的范围聚合。此聚合与普通的 range 聚合之间的主要区别在于,fromto 值可以用 日期计算表达式表示,并且还可以指定返回 fromto 响应字段的日期格式。请注意,此聚合包括每个范围的 from 值,并排除 to 值。

示例

resp = client.search(
    index="sales",
    size="0",
    aggs={
        "range": {
            "date_range": {
                "field": "date",
                "format": "MM-yyyy",
                "ranges": [
                    {
                        "to": "now-10M/M"
                    },
                    {
                        "from": "now-10M/M"
                    }
                ]
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'sales',
  size: 0,
  body: {
    aggregations: {
      range: {
        date_range: {
          field: 'date',
          format: 'MM-yyyy',
          ranges: [
            {
              to: 'now-10M/M'
            },
            {
              from: 'now-10M/M'
            }
          ]
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "sales",
  size: 0,
  aggs: {
    range: {
      date_range: {
        field: "date",
        format: "MM-yyyy",
        ranges: [
          {
            to: "now-10M/M",
          },
          {
            from: "now-10M/M",
          },
        ],
      },
    },
  },
});
console.log(response);
POST /sales/_search?size=0
{
  "aggs": {
    "range": {
      "date_range": {
        "field": "date",
        "format": "MM-yyyy",
        "ranges": [
          { "to": "now-10M/M" },  
          { "from": "now-10M/M" } 
        ]
      }
    }
  }
}

< 现在减去 10 个月,向下舍入到月初。

>= 现在减去 10 个月,向下舍入到月初。

在上面的示例中,我们创建了两个范围桶,第一个桶将“放入”所有日期早于 10 个月前的文档,第二个桶将“放入”所有日期自 10 个月前的文档

响应

{
  ...
  "aggregations": {
    "range": {
      "buckets": [
        {
          "to": 1.4436576E12,
          "to_as_string": "10-2015",
          "doc_count": 7,
          "key": "*-10-2015"
        },
        {
          "from": 1.4436576E12,
          "from_as_string": "10-2015",
          "doc_count": 0,
          "key": "10-2015-*"
        }
      ]
    }
  }
}

如果格式或日期值不完整,则日期范围聚合会将任何缺失的组件替换为默认值。请参阅缺失的日期组件

缺失值

编辑

missing 参数定义了应如何处理缺少值的文档。默认情况下,它们将被忽略,但也可以将它们视为具有值。这是通过添加一组 fieldname : value 映射来指定每个字段的默认值来完成的。

resp = client.search(
    index="sales",
    size="0",
    aggs={
        "range": {
            "date_range": {
                "field": "date",
                "missing": "1976/11/30",
                "ranges": [
                    {
                        "key": "Older",
                        "to": "2016/02/01"
                    },
                    {
                        "key": "Newer",
                        "from": "2016/02/01",
                        "to": "now/d"
                    }
                ]
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'sales',
  size: 0,
  body: {
    aggregations: {
      range: {
        date_range: {
          field: 'date',
          missing: '1976/11/30',
          ranges: [
            {
              key: 'Older',
              to: '2016/02/01'
            },
            {
              key: 'Newer',
              from: '2016/02/01',
              to: 'now/d'
            }
          ]
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "sales",
  size: 0,
  aggs: {
    range: {
      date_range: {
        field: "date",
        missing: "1976/11/30",
        ranges: [
          {
            key: "Older",
            to: "2016/02/01",
          },
          {
            key: "Newer",
            from: "2016/02/01",
            to: "now/d",
          },
        ],
      },
    },
  },
});
console.log(response);
POST /sales/_search?size=0
{
   "aggs": {
       "range": {
           "date_range": {
               "field": "date",
               "missing": "1976/11/30",
               "ranges": [
                  {
                    "key": "Older",
                    "to": "2016/02/01"
                  }, 
                  {
                    "key": "Newer",
                    "from": "2016/02/01",
                    "to" : "now/d"
                  }
              ]
          }
      }
   }
}

date 字段中没有值的文档将被添加到 “Older” 桶中,就好像它们的日期值为 "1976-11-30"。

日期格式/模式

编辑

此信息复制自 DateTimeFormatter

所有 ASCII 字母都保留为格式模式字母,定义如下

符号 含义 表示 示例

G

纪元

文本

公元; Anno Domini; A

u

2004; 04

y

纪元年

2004; 04

D

年中的天数

数字

189

M/L

一年中的月份

数字/文本

7; 07; Jul; July; J

d

月份中的天数

数字

10

Q/q

一年中的季度

数字/文本

3; 03; Q3; 第 3 季度

Y

基于周的年份

1996; 96

w

基于周的年份中的周数

数字

27

W

月份中的周数

数字

4

E

星期几

文本

周二; 星期二; T

e/c

本地化的星期几

数字/文本

2; 02; 周二; 星期二; T

F

月份中的周数

数字

3

a

一天中的上午/下午

文本

下午

h

上午/下午的时钟小时数(1-12)

数字

12

K

上午/下午的小时数(0-11)

数字

0

k

一天中的时钟小时数(1-24)

数字

0

H

一天中的小时数(0-23)

数字

0

m

分钟

数字

30

s

数字

55

S

秒的分数

分数

978

A

一天中的毫秒

数字

1234

n

秒的纳秒

数字

987654321

N

一天的纳秒

数字

1234000000

V

时区 ID

时区 ID

美国/洛杉矶; Z; -08:30

z

时区名称

时区名称

太平洋标准时间; PST

O

本地化的时区偏移量

偏移量-O

GMT+8; GMT+08:00; UTC-08:00;

X

零的 时区偏移量Z

偏移量-X

Z; -08; -0830; -08:30; -083015; -08:30:15;

x

时区偏移量

偏移量-x

+0000; -08; -0830; -08:30; -083015; -08:30:15;

Z

时区偏移量

偏移量-Z

+0000; -0800; -08:00;

p

填充下一个

填充修饰符

1

'

文本的转义符

分隔符

''

单引号

字面量

'

[

可选部分开始

]

可选部分结束

#

保留供将来使用

{

保留供将来使用

}

模式字母的计数决定了格式。

文本
文本样式是根据使用的模式字母的数量确定的。少于 4 个模式字母将使用短格式。正好 4 个模式字母将使用完整格式。正好 5 个模式字母将使用窄格式。模式字母 Lcq 指定文本样式的独立形式。
数字
如果字母计数为 1,则使用最小的位数且不带填充输出该值。否则,位数的计数将用作输出字段的宽度,并根据需要使用零填充该值。以下模式字母对字母的计数有限制。只能指定一个字母 cF。最多可以指定两个字母 dHhKkms。最多可以指定三个字母 D
数字/文本
如果模式字母的计数为 3 或更大,请使用上面的文本规则。否则,请使用上面的数字规则。
分数
将秒的纳秒字段作为秒的分数输出。纳秒值有 9 位数字,因此模式字母的计数为 1 到 9。如果小于 9,则纳秒值将被截断,仅输出最重要的数字。
字母的计数决定了使用填充的最小字段宽度。如果字母的计数为 2,则使用简化的两位数形式。对于打印,这将输出最右边的两位数字。对于解析,这将使用 2000 的基值进行解析,从而得到 2000 到 2099(包括 2000 和 2099)范围内的年份。如果字母的计数小于 4(但不是 2),则仅针对负数年份输出符号,如 SignStyle.NORMAL 所示。否则,如果超出填充宽度,则输出符号,如 SignStyle.EXCEEDS_PAD 所示。
ZoneId
这将输出时区 ID,例如 Europe/Paris。如果字母的计数为 2,则输出时区 ID。任何其他字母计数都会抛出 IllegalArgumentException
时区名称
这将输出时区 ID 的显示名称。如果字母的计数为 1、2 或 3,则输出短名称。如果字母的计数为 4,则输出全名。五个或更多字母会抛出 IllegalArgumentException
偏移量 X 和 x
这将根据模式字母的数量设置偏移量的格式。一个字母仅输出小时,例如 +01,除非分钟不为零,在这种情况下也会输出分钟,例如 +0130。两个字母输出小时和分钟,不带冒号,例如 +0130。三个字母输出小时和分钟,带有冒号,例如 +01:30。四个字母输出小时、分钟和可选的秒,不带冒号,例如 +013015。五个字母输出小时、分钟和可选的秒,带有冒号,例如 +01:30:15。六个或更多字母会抛出 IllegalArgumentException。当要输出的偏移量为零时,模式字母 X(大写)将输出 Z,而模式字母 x(小写)将输出 +00+0000+00:00
偏移量 O
这将根据模式字母的数量设置本地化偏移量的格式。一个字母输出本地化偏移量的短格式,该短格式为本地化的偏移量文本,例如 GMT,小时不带前导零,可选的 2 位分钟和秒(如果不为零)以及冒号,例如 GMT+8。四个字母输出完整形式,该形式为本地化的偏移量文本,例如 GMT,带有 2 位小时和分钟字段,如果秒字段不为零,则带有可选的秒字段,以及冒号,例如 `GMT+08:00`。任何其他字母计数都会抛出 IllegalArgumentException
偏移量 Z
这将根据模式字母的数量设置偏移量的格式。一、二或三个字母输出小时和分钟,不带冒号,例如 +0130。当偏移量为零时,输出将为 +0000。四个字母输出本地化偏移量的完整形式,等效于偏移量-O 的四个字母。如果偏移量为零,则输出将为相应的本地化偏移量文本。五个字母输出小时、分钟以及可选的秒(如果不为零),带有冒号。如果偏移量为零,则输出 Z。六个或更多字母会抛出 IllegalArgumentException。
可选部分
可选部分标记的工作方式与调用 DateTimeFormatterBuilder.optionalStart()DateTimeFormatterBuilder.optionalEnd() 完全相同。
填充修饰符
修改紧随其后的模式,使其填充空格。填充宽度由模式字母的数量决定。这与调用 DateTimeFormatterBuilder.padNext(int) 相同。

例如,ppH 输出用空格在左侧填充至宽度 2 的一天中的小时。

任何无法识别的字母都是错误。任何非字母字符,除了 []{}# 和单引号之外,都将直接输出。尽管如此,建议在所有要直接输出的字符周围使用单引号,以确保将来的更改不会破坏您的应用程序。

日期范围聚合中的时区

编辑

可以通过指定 time_zone 参数将日期从另一个时区转换为 UTC。

时区可以指定为 ISO 8601 UTC 偏移量(例如 +01:00 或 -08:00),也可以指定为 TZ 数据库中的时区 ID 之一。

time_zone 参数也应用于日期计算表达式中的舍入。例如,要舍入到 CET 时区的一天开始时间,您可以执行以下操作

resp = client.search(
    index="sales",
    size="0",
    aggs={
        "range": {
            "date_range": {
                "field": "date",
                "time_zone": "CET",
                "ranges": [
                    {
                        "to": "2016/02/01"
                    },
                    {
                        "from": "2016/02/01",
                        "to": "now/d"
                    },
                    {
                        "from": "now/d"
                    }
                ]
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'sales',
  size: 0,
  body: {
    aggregations: {
      range: {
        date_range: {
          field: 'date',
          time_zone: 'CET',
          ranges: [
            {
              to: '2016/02/01'
            },
            {
              from: '2016/02/01',
              to: 'now/d'
            },
            {
              from: 'now/d'
            }
          ]
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "sales",
  size: 0,
  aggs: {
    range: {
      date_range: {
        field: "date",
        time_zone: "CET",
        ranges: [
          {
            to: "2016/02/01",
          },
          {
            from: "2016/02/01",
            to: "now/d",
          },
          {
            from: "now/d",
          },
        ],
      },
    },
  },
});
console.log(response);
POST /sales/_search?size=0
{
   "aggs": {
       "range": {
           "date_range": {
               "field": "date",
               "time_zone": "CET",
               "ranges": [
                  { "to": "2016/02/01" }, 
                  { "from": "2016/02/01", "to" : "now/d" }, 
                  { "from": "now/d" }
              ]
          }
      }
   }
}

此日期将转换为 2016-02-01T00:00:00.000+01:00

now/d 将舍入到 CET 时区的一天开始时间。

键控响应

编辑

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

resp = client.search(
    index="sales",
    size="0",
    aggs={
        "range": {
            "date_range": {
                "field": "date",
                "format": "MM-yyy",
                "ranges": [
                    {
                        "to": "now-10M/M"
                    },
                    {
                        "from": "now-10M/M"
                    }
                ],
                "keyed": True
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'sales',
  size: 0,
  body: {
    aggregations: {
      range: {
        date_range: {
          field: 'date',
          format: 'MM-yyy',
          ranges: [
            {
              to: 'now-10M/M'
            },
            {
              from: 'now-10M/M'
            }
          ],
          keyed: true
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "sales",
  size: 0,
  aggs: {
    range: {
      date_range: {
        field: "date",
        format: "MM-yyy",
        ranges: [
          {
            to: "now-10M/M",
          },
          {
            from: "now-10M/M",
          },
        ],
        keyed: true,
      },
    },
  },
});
console.log(response);
POST /sales/_search?size=0
{
  "aggs": {
    "range": {
      "date_range": {
        "field": "date",
        "format": "MM-yyy",
        "ranges": [
          { "to": "now-10M/M" },
          { "from": "now-10M/M" }
        ],
        "keyed": true
      }
    }
  }
}

响应

{
  ...
  "aggregations": {
    "range": {
      "buckets": {
        "*-10-2015": {
          "to": 1.4436576E12,
          "to_as_string": "10-2015",
          "doc_count": 7
        },
        "10-2015-*": {
          "from": 1.4436576E12,
          "from_as_string": "10-2015",
          "doc_count": 0
        }
      }
    }
  }
}

也可以自定义每个范围的键

resp = client.search(
    index="sales",
    size="0",
    aggs={
        "range": {
            "date_range": {
                "field": "date",
                "format": "MM-yyy",
                "ranges": [
                    {
                        "from": "01-2015",
                        "to": "03-2015",
                        "key": "quarter_01"
                    },
                    {
                        "from": "03-2015",
                        "to": "06-2015",
                        "key": "quarter_02"
                    }
                ],
                "keyed": True
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'sales',
  size: 0,
  body: {
    aggregations: {
      range: {
        date_range: {
          field: 'date',
          format: 'MM-yyy',
          ranges: [
            {
              from: '01-2015',
              to: '03-2015',
              key: 'quarter_01'
            },
            {
              from: '03-2015',
              to: '06-2015',
              key: 'quarter_02'
            }
          ],
          keyed: true
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "sales",
  size: 0,
  aggs: {
    range: {
      date_range: {
        field: "date",
        format: "MM-yyy",
        ranges: [
          {
            from: "01-2015",
            to: "03-2015",
            key: "quarter_01",
          },
          {
            from: "03-2015",
            to: "06-2015",
            key: "quarter_02",
          },
        ],
        keyed: true,
      },
    },
  },
});
console.log(response);
POST /sales/_search?size=0
{
  "aggs": {
    "range": {
      "date_range": {
        "field": "date",
        "format": "MM-yyy",
        "ranges": [
          { "from": "01-2015", "to": "03-2015", "key": "quarter_01" },
          { "from": "03-2015", "to": "06-2015", "key": "quarter_02" }
        ],
        "keyed": true
      }
    }
  }
}

响应

{
  ...
  "aggregations": {
    "range": {
      "buckets": {
        "quarter_01": {
          "from": 1.4200704E12,
          "from_as_string": "01-2015",
          "to": 1.425168E12,
          "to_as_string": "03-2015",
          "doc_count": 5
        },
        "quarter_02": {
          "from": 1.425168E12,
          "from_as_string": "03-2015",
          "to": 1.4331168E12,
          "to_as_string": "06-2015",
          "doc_count": 2
        }
      }
    }
  }
}