文章目录
- 官方文档
- 概述
- Composite Aggregation 概述
- 示例:基本分页查询
- 分页:获取下一页结果
- 使用场景
- 注意事项
官方文档
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-composite-aggregation.html#_pagination
概述
当需要分页查询大量的桶时composite 聚合可以通过分页的方式逐步获取桶结果,避免一次性返回大量的桶 。
与传统分页方法不同,composite aggregation
并不基于结果的偏移量(offset),而是基于聚合桶的游标机制来实现分页,从而避免了性能瓶颈。
Composite Aggregation 概述
composite aggregation
是 Elasticsearch 中的一种特殊聚合方式,适用于需要分页展示的聚合结果。它与传统的聚合方式不同,采用了基于游标的分页模型。composite aggregation
不依赖 from
和 size
来进行分页,而是通过 after
参数来指定从某个特定桶之后开始返回数据,从而实现分页。
示例:基本分页查询
假设我们有一个索引,名称为 your_index_name
,其中包含多个文档,每个文档都有一个字段 your_field_name
。我们希望根据这个字段进行分页查询,并且每次返回 10 个聚合结果。
以下是一个基础的分页查询示例:
GET /your_index_name/_search
{
"size": 0,
"aggs": {
"my_composite_agg": {
"composite": {
"size": 10,
"sources": [
{
"my_terms_agg": {
"terms": {
"field": "your_field_name"
}
}
}
]
}
}
}
}
-
size
设置为 0:由于我们使用的是聚合查询,而非文档查询,所以不需要返回文档内容。size: 0
意味着查询结果中不会包含文档,只会返回聚合的结果。 -
composite
聚合:这是我们实现分页的关键。composite
聚合会根据指定的聚合方式返回一个分页的桶(bucket)结果。每个桶代表了根据your_field_name
字段分组后的数据。 -
size: 10
:表示每次返回 10 个桶,即每页 10 条聚合结果。 -
sources
:这是定义如何分组数据的部分。这里,我们使用了terms
聚合,根据your_field_name
字段的值对文档进行分组。
分页:获取下一页结果
要实现分页,我们需要使用 after
参数来指示从哪个位置开始返回数据。这个参数的值是上一个查询返回的最后一个桶的 key
值。
下面是如何获取第二页结果的示例:
GET /your_index_name/_search
{
"size": 0,
"aggs": {
"my_composite_agg": {
"composite": {
"size": 10,
"after": ["bucket_key_from_first_page"], // 第一页的最后一个桶的key值
"sources": [
{
"my_terms_agg": {
"terms": {
"field": "your_field_name"
}
}
}
]
}
}
}
}
-
after
参数:这是实现分页的关键,after
参数的值应该是上一页结果的最后一个桶的key
值(可以通过上一页查询结果中的after_key
获取)。after
参数告诉 Elasticsearch 从哪个位置开始返回数据,从而实现分页。 -
获取
after_key
:在每次查询的返回结果中,除了聚合的结果之外,还可以看到一个after_key
字段,这个字段就是下一次分页查询所需要使用的after
参数的值。
例如,假设第一次查询的返回结果包含以下聚合信息:
{
"aggregations": {
"my_composite_agg": {
"buckets": [
{
"key": { "your_field_name": "value1" },
"doc_count": 10
},
{
"key": { "your_field_name": "value2" },
"doc_count": 15
},
// ... 更多桶
],
"after_key": { "your_field_name": "value2" }
}
}
}
在第二次分页查询时,我们需要使用 after_key
中的 your_field_name: "value2"
作为 after
参数的值,以此来获取下一页的结果。
官方案例
GET /_search
{
"size": 0,
"aggs": {
"my_buckets": {
"composite": {
"size": 2,
"sources": [
{ "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d" } } },
{ "product": { "terms": { "field": "product" } } }
]
}
}
}
}
返回
{
...
"aggregations": {
"my_buckets": {
"after_key": {
"date": 1494288000000,
"product": "mad max"
},
"buckets": [
{
"key": {
"date": 1494201600000,
"product": "rocky"
},
"doc_count": 1
},
{
"key": {
"date": 1494288000000,
"product": "mad max"
},
"doc_count": 2
}
]
}
}
}
下次查询
GET /_search
{
"size": 0,
"aggs": {
"my_buckets": {
"composite": {
"size": 2,
"sources": [
{ "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d", "order": "desc" } } },
{ "product": { "terms": { "field": "product", "order": "asc" } } }
],
"after": { "date": 1494288000000, "product": "mad max" }
}
}
}
}
使用场景
composite aggregation
非常适用于以下场景:
-
大量数据分页:当桶数据量非常大时,使用
composite aggregation
可以避免偏移的性能开销。 -
基于字段的分组分页:如果需要对某个字段进行分组并进行分页,
composite aggregation
是最合适的方式。 -
避免数据丢失:使用传统分页方法时,由于数据的变动可能导致查询结果发生偏移,从而可能出现重复或遗漏的情况。
composite aggregation
通过游标机制避免了这个问题。
注意事项
-
after
参数的类型:after
参数的值类型与sources
中定义的聚合字段类型保持一致。例如,如果你的字段是字符串类型,那么after
参数应该是字符串类型;如果是数字类型,那么应该是数字类型。 -
分页的顺序:
composite aggregation
是基于聚合桶的游标来分页的,因此分页的顺序依赖于聚合字段的值排序。如果数据分布不均,可能会导致每页的桶数不一致。 -
限制聚合桶数:虽然可以通过
size
参数控制每页的结果数,但需要注意的是,composite aggregation
每次最多只会返回 10,000 个桶。如果你的分页范围超过这个数量,可能需要对数据进行分片或者其他优化。