# 聚合分析增强
在处理大规模数据时，用户经常面临聚合查询性能低、分析效率低的问题。CSS服务的Elasticsearch集群聚合增强功能通过向量化技术和数据聚簇优化，显著提升大规模数据的聚合查询分析性能，帮助用户在复杂数据场景中实现高效分析和提升业务决策效率。
#### 功能介绍
聚合增强功能的核心原理是通过合理设置排序键（Sort Key）和聚簇键（Clustering Key）在数据写入时对数据进行预排序和物理聚簇，从而减少查询时聚合过程中的数据扫描和计算开销。
- 排序键：数据按指定字段（如时间戳）顺序存储，确保相同值或相近值的文档在磁盘上连续分布。
- 聚簇键：作为排序键的前缀子集（如各城市订单数），进一步将数据聚簇，使聚合操作可批量处理连续数据块，而非逐条遍历。
 
例如，对于包含region、host、value三个字段的索引，在写入时文档将按region、host、value字段顺序排序，并按region和host字段进行聚簇存储。相同region和host组合的文档在物理上连续存储，且在聚簇内部按value字段的有序排列。
聚合查询可直接按聚簇键（region和host）进行查询，或在同一聚簇内基于value字段的取值范围进行批量查询，从而提升查询效率。
图1聚合增强示例   
![](https://support.huaweicloud.com/usermanual-css/figure/zh-cn_image_0000002510653374.png "点击放大")
表1聚合增强的适用场景 
| 场景         | 描述                                                            |
|:---|:---|
| 低基字段聚合    | 字段值种类较少，适合分组聚合。例如，统计各城市订单数量时，数据聚簇后可快速定位并批量处理。                  |
| 高基字段聚合   | 字段值种类繁多，适合直方图聚合。例如，按小时统计访问量时，使用排序键可加速区间数据的聚合。                 |
| 低基和高基字段混合聚合 | 先对低基字段使用聚簇键进行分组（如各城市订单），再对高基字段使用排序键进行直方图聚合（如时间），通过多级聚簇提升混合查询效率。 |
   
#### 约束限制
Elasticsearch集群仅7.10.2版本支持聚合增强。
#### 登录Kibana
登录Kibana进入命令执行页面。Elasticsearch集群支持多种客户端访问，本文仅以CSS服务集成的Kibana为例介绍配置指导。
1. 登录[云搜索服务管理控制台](https://console.huaweicloud.com/elasticsearch/)。
2. 在左侧导航栏，选择"集群管理 \> Elasticsearch"。
3. 在集群列表，选择目标集群，单击操作列的"Kibana"，登录Kibana。
4. 在Kibana左侧导航栏选择"Dev Tools"，进入操作页面。 控制台左侧是命令输入框，其右侧的三角形图标为执行按钮，右侧区域则显示执行结果。
   
 
#### 低基字段聚合
低基字段一般采用分组聚合，在排序的情况下具备较好的数据聚簇性，利于批量处理数据。
例如，当需要对"city"和"product"这两个低基字段进行聚合增强时，可以执行以下操作步骤实现聚合任务。
1. 执行如下命令，设置索引testindex。
   ```
   PUT testindex
   {
     "mappings": {
       "properties": {
         "date": {
           "type": "date",
           "format": "yyyy-MM-dd"
         },
         "city": {
           "type": "keyword"
         },
         "product": {
           "type": "keyword"
         },
         "trade": {
           "type": "double"
         }
       }
     },
     "settings": {
       "index": {
         "search": {
           "turbo": {
             "enabled": "true" 
           }
         },
         "sort": {
           "field": [
             "city",
             "product"
           ]
         },
         "cluster": {
           "field": [
             "city",
             "product"
           ]
         }
       }
     }
   }
   ```
   表2低基字段聚合的参数说明 
   | 参数                          | 类型             | 默认值    | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
   |:---|:---|:---|:---|
   | index.search.turbo.enabled | Boolean         | false | 是否启用聚合增强功能。使用聚合分析时必须启用聚合增强功能。 取值范围： - false：不启用聚合增强。  - true：启用聚合增强。   |
   | index.sort.field          | Array of strings | 无      | 指定排序键。排序键用于定义文档排序所依据的字段。 在配置排序键时，可以指定一个或多个字段。当多个字段被指定时，排序将按照字段的顺序依次进行。第一个字段的排序结果将作为主要排序依据，第二个字段则在第一个字段排序结果的基础上进行次级排序，以此类推。 取值范围：必须是索引包含的字段。                                                                                                                                                                                                                                              |
   | index.cluster.field          | Array of strings | 无        | 指定聚簇键。聚簇键用于对文档进行聚簇处理，具有相同键值的文档会被归类到同一聚簇中。 在进行聚合操作时，同一聚簇内的文档能够被批量处理，从而显著提升聚合性能。 约束限制：聚簇键必须是排序键的前缀子集。 取值范围：必须是索引包含的字段。                                                                                                                                                                                             |
      
   
2. 执行如下命令，导入样例数据。
   ```
   PUT /_bulk
   { "index": { "_index": "testindex", "_id": "1" } }
   { "date": "2025-01-01", "city": "cityA", "product": "books", "trade": 3000.0}
   { "index": { "_index": "testindex", "_id": "2" } }
   { "date": "2025-01-02", "city": "cityA", "product": "books", "trade": 1000.0}
   { "index": { "_index": "testindex", "_id": "3" } }
   { "date": "2025-01-01", "city": "cityA", "product": "bottles", "trade": 100.0}
   { "index": { "_index": "testindex", "_id": "4" } }
   { "date": "2025-01-02", "city": "cityA", "product": "bottles", "trade": 300.0}
   { "index": { "_index": "testindex", "_id": "5" } }
   { "date": "2025-01-01", "city": "cityB", "product": "books", "trade": 7000.0}
   { "index": { "_index": "testindex", "_id": "6" } }
   { "date": "2025-01-02", "city": "cityB", "product": "books", "trade": 1000.0}
   ```
   
3. 执行查询命令，实现低基字段聚合查询。 例如，查询不同city下每个product的trade平均值：
   ```
   POST testindex/_search
   {
     "size": 0,
     "aggs": {
       "groupby_city": {
         "terms": {
           "field": "city"
         },
         "aggs": {
           "groupby_product": {
             "terms": {
               "field": "product"
             },
             "aggs": {
               "avg_trade": {
                 "avg": {
                   "field": "trade"
                 }
               }
             }
           }
         }
       }
     }
   }
   ```
   
 
#### 高基字段聚合
高基字段一般采用排序键进行直方图分组聚合，利于处理某个区间内的数据。
例如，当需要对典型的高基字段"date"进行聚合增强时，可以执行以下操作步骤实现聚合任务。
1. 执行如下命令，设置索引testindex。
   ```
   PUT testindex
   {
     "mappings": {
       "properties": {
         "date": {
           "type": "date",
           "format": "yyyy-MM-dd"
         },
         "score": {
           "type": "double"
         }
       }
     },
     "settings": {
       "index": {
         "search": {
           "turbo": {
             "enabled": "true" 
           }
         },
         "sort": {
           "field": [
             "date"
           ]
         }
       }
     }
   }
   ```
   表3高基字段聚合的参数说明 
   | 参数                        | 类型               | 默认值 | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
   |:---|:---|:---|:---|
   | index.search.turbo.enabled | Boolean        | false | 是否启用聚合增强功能。使用聚合分析时必须启用聚合增强功能。 取值范围： - false：不启用聚合增强。  - true：启用聚合增强。   |
   | index.sort.field          | Array of strings | 无    | 指定排序键。排序键用于定义文档排序所依据的字段。 在配置排序键时，可以指定一个或多个字段。当多个字段被指定时，排序将按照字段的顺序依次进行。第一个字段的排序结果将作为主要排序依据，第二个字段则在第一个字段排序结果的基础上进行次级排序，以此类推。 取值范围：必须是索引包含的字段。                                                                                                                                                                                                                                             |
      
   
2. 执行如下命令，导入样例数据。
   ```
   PUT /_bulk
   { "index": { "_index": "testindex", "_id": "1" } }
   { "date": "2025-01-01", "score": "12.0"}
   { "index": { "_index": "testindex", "_id": "2" } }
   { "date": "2025-01-02","score": "24.0"}
   { "index": { "_index": "testindex", "_id": "3" } }
   { "date": "2025-01-01","score": "53.0"}
   { "index": { "_index": "testindex", "_id": "4" } }
   { "date": "2025-01-02", "score": "22.0"}
   { "index": { "_index": "testindex", "_id": "5" } }
   { "date": "2025-01-01", "score": "99.0"}
   { "index": { "_index": "testindex", "_id": "6" } }
   { "date": "2025-01-02","score": "26.0"}
   ```
   
3. 执行查询命令，实现高基字段聚合查询。 该聚合任务是对时间字段date做直方图分组，然后求score的平均值。
   ```
   POST testindex/_search?pretty
   {
     "size": 0,
     "aggs": {
       "groupbytime": {
         "date_histogram": {
           "field": "date",
           "calendar_interval": "day"
         },
         "aggs": {
           "avg_score": {
             "avg": {
               "field": "score"
             }
           }
         }
       }
     }
   }
   ```
   
 
#### 低基和高基字段混合聚合
在低基字段和高基字段混合的场景下，一般先对低基字段使用聚簇键进行分组，然后再对高基字段使用排序键进行直方图聚合。
例如，当需要先对"city"低基字段进行分组，再对"product"低基字段进行分组，最后对"date"高基字段进行直方图分组时，可以执行以下操作步骤实现聚合任务。
1. 执行如下命令，设置索引testindex。
   ```
   PUT testindex
   {
     "mappings": {
       "properties": {
         "date": {
           "type": "date",
           "format": "yyyy-MM-dd"
         },
         "city": {
           "type": "keyword"
         },
         "product": {
           "type": "keyword"
         },
         "trade": {
           "type": "double"
         }
       }
     },
     "settings": {
       "index": {
         "search": {
           "turbo": {
             "enabled": "true"
           }
         },
         "sort": { 
           "field": [
             "city",
             "product",
             "date"
           ]
         },
         "cluster": {
           "field": [
             "city",
             "product"
           ]
         }
       }
     }
   }
   ```
   表4低基和高基字段混合聚合的参数说明 
   | 参数                        | 类型               | 默认值      | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
   |:---|:---|:---|:---|
   | index.search.turbo.enabled | Boolean         | false | 是否启用聚合增强功能。使用聚合分析时必须启用聚合增强功能。 取值范围： - false：不启用聚合增强。  - true：启用聚合增强。   |
   | index.sort.field           | Array of strings  | 无        | 指定排序键。排序键用于定义文档排序所依据的字段。 在配置排序键时，可以指定一个或多个字段。当多个字段被指定时，排序将按照字段的顺序依次进行。第一个字段的排序结果将作为主要排序依据，第二个字段则在第一个字段排序结果的基础上进行次级排序，以此类推。 约束限制：高基字段必须在排序键中，且高基字段必须在最后一个低基字段后面。 取值范围：必须是索引包含的字段。                                                                                                                                 |
   | index.cluster.field        | Array of strings | 无       | 指定聚簇键。聚簇键用于对文档进行聚簇处理，具有相同键值的文档会被归类到同一聚簇中。 在进行聚合操作时，同一聚簇内的文档能够被批量处理，从而显著提升聚合性能。 约束限制：聚簇键必须是排序键的前缀子集。 取值范围：必须是索引包含的字段。                                                                                                                                                                                             |
      
   
2. 执行如下命令，导入样例数据。
   ```
   PUT /_bulk
   { "index": { "_index": "testindex", "_id": "1" } }
   { "date": "2025-01-01", "city": "cityA", "product": "books", "trade": 3000.0}
   { "index": { "_index": "testindex", "_id": "2" } }
   { "date": "2025-01-02", "city": "cityA", "product": "books", "trade": 1000.0}
   { "index": { "_index": "testindex", "_id": "3" } }
   { "date": "2025-01-01", "city": "cityA", "product": "bottles", "trade": 100.0}
   { "index": { "_index": "testindex", "_id": "4" } }
   { "date": "2025-01-02", "city": "cityA", "product": "bottles", "trade": 300.0}
   { "index": { "_index": "testindex", "_id": "5" } }
   { "date": "2025-01-01", "city": "cityB", "product": "books", "trade": 7000.0}
   { "index": { "_index": "testindex", "_id": "6" } }
   { "date": "2025-01-02", "city": "cityB", "product": "books", "trade": 1000.0}
   ```
   
3. 执行查询命令，实现低基和高基字段混合聚合查询。 例如，查询不同city下每个product的在date字段每天的trade平均值：
   ```
   POST testindex/_search
   {
     "size": 0,
     "aggs": {
       "groupby_region": {
         "terms": {
           "field": "city"
         },
         "aggs": {
           "groupby_host": {
             "terms": {
               "field": "product"
             },
             "aggs": {
               "groupby_timestamp": {
                 "date_histogram": {
                   "field": "date",
                   "interval": "day"
                 },
                 "aggs": {
                   "avg_score": {
                     "avg": {
                       "field": "trade"
                     }
                   }
                 }
               }
             }
           }
         }
       }
     }
   }
   ```
   
 
#### 性能测试对比
**测试环境**
- 数据集： esrally nyc_taxis数据集
- 集群规格： 4U16G 100GB高IO \* 3节点
 
**测试步骤**
1. 在集群中创建索引模板，指定排序键和关闭聚合增强。
   ```
   PUT /_template/nyc_taxis
   {
     "template": "nyc_taxis*",
     "settings": {
       "index.search.turbo.enabled": false,
       "index.sort.field": "dropoff_datetime",
       "number_of_shards": 3,
       "number_of_replicas": 0
     }
   }
   ```
   
2. 使用esrally执行nyc_taxis数据集的测试，得到关闭聚合增强时的结果。
3. 在同一个集群中创建索引模板，指定排序键和开启聚合增强。
   ```
   PUT /_template/nyc_taxis
   {
     "template": "nyc_taxis*",
     "settings": {
       "index.search.turbo.enabled": true,
       "index.sort.field": "dropoff_datetime",
       "number_of_shards": 3,
       "number_of_replicas": 0
     }
   }
   ```
   
4. 使用esrally执行nyc_taxis数据集的测试，得到开启聚合增强时的结果。
 
**测试结果**
本次测试仅关注针对"dropoff_datetime"聚合的查询结果，即只关注"autohisto_agg"和"date_histogram_agg"两个任务的结果，以下为该任务的测试结果对比。
| Metric                        | Task               | Unit  | 关闭聚合增强                                                                                                                ||| 开启聚合增强                                                                                                                ||| 关闭聚合增强  | 开启聚合增强 | open/close | 结论          |
| Metric                        | Task               | Unit  | 测试轮次1    | 测试轮次2   | 测试轮次3       | 测试轮次1   | 测试轮次2  | 测试轮次3    | 均值     | 均值    | open/close | 结论          |
|:---|:---|:---|:---|:---|:---|:---|:---|:---|:---|:---|:---|:---|
| Min Throughput                | autohisto_agg       | ops/s  | 4.42     | 4.44   | 4.43     | 11.66  | 11.94     | 11.96  | 4.43    | 11.85    | 2.68         | 吞吐量提升2.5倍以上 |
| Mean Throughput              | autohisto_agg         | ops/s   | 4.50     | 4.46  | 4.44      | 11.81     | 11.99    | 12.00  | 4.47     | 11.93  | 2.67           | 吞吐量提升2.5倍以上 |
| Median Throughput               | autohisto_agg       | ops/s   | 4.51     | 4.46  | 4.44   | 11.83    | 11.98     | 12.00   | 4.47    | 11.94   | 2.67         | 吞吐量提升2.5倍以上 |
| Max Throughput               | autohisto_agg       | ops/s    | 4.54   | 4.48   | 4.45   | 11.90   | 12.07 | 12.02  | 4.49    | 12.00 | 2.67         | 吞吐量提升2.5倍以上 |
| 100th percentile latency     | autohisto_agg       | ms     | 216.30 | -        | -          | -      | 84.56   | 80.38 | 216.30  | 82.47  | 0.38         | 时延下降60%以上  |
| 100th percentile service time | autohisto_agg       | ms     | 216.30  | -      | -        | -        | 84.56    | 80.38  | 216.30     | 82.47  | 0.38          | 时延下降60%以上  |
| error rate                     | autohisto_agg      | %       | 0       | 0        | 0        | 0       | 0      | 0        | 0      | 0      | 0              | -             |
| Min Throughput               | date_histogram_agg    | ops/s | 4.72     | 4.67    | 4.65     | 12.57   | 12.40    | 12.59   | 4.68       | 12.52   | 2.68           | 吞吐量提升2.5倍以上   |
| Mean Throughput                | date_histogram_agg | ops/s   | 4.73   | 4.67      | 4.67     | 12.61  | 12.46   | 12.61   | 4.69       | 12.56   | 2.68           | 吞吐量提升2.5倍以上   |
| Median Throughput            | date_histogram_agg  | ops/s    | 4.73     | 4.67     | 4.67   | 12.62    | 12.46  | 12.60  | 4.69     | 12.56 | 2.68          | 吞吐量提升2.5倍以上   |
| Max Throughput                  | date_histogram_agg   | ops/s | 4.74    | 4.67    | 4.67      | 12.64   | 12.49 | 12.63   | 4.69     | 12.59   | 2.68           | 吞吐量提升2.5倍以上   |
| 50th percentile latency       | date_histogram_agg | ms     | 202.61    | 218.09 | 213.43    | 77.64  | 76.02    | 82.63    | 211.38 | 78.77  | 0.37          | 时延下降60%以上    |
| 100th percentile latency      | date_histogram_agg  | ms     | 207.35 | 223.88   | 246.63  | 77.99 | -        | -        | 225.95  | 77.99   | 0.35         | 时延下降60%以上    |
| 50th percentile service time  | date_histogram_agg  | ms       | 202.61  | 218.09  | 213.43 | 77.64  | 76.02  | 82.63   | 211.38  | 78.77 | 0.37          | 时延下降60%以上    |
| 100th percentile service time | date_histogram_agg | ms      | 207.35   | 223.88 | 246.63    | 77.99    | -       | -      | 225.95   | 77.99 | 0.35          | 时延下降60%以上    |
| error rate                      | date_histogram_agg | %      | 0         | 0       | 0       | 0     | 0      | 0     | 0        | 0      | 0            | -           |
   
**测试结论**
在集群配置相同的情况下，开启聚合增强后，聚合性能显著提升，查询吞吐量提升2.5倍以上，查询时延下降60%以上。
