索引汇总

时间序列数据会增加存储成本,对集群健康造成压力,并随着时间的推移降低聚合速度。索引汇总可以让你通过将旧数据汇总到摘要索引中来定期降低数据粒度。

你选择感兴趣的字段,并使用索引汇总创建一个仅包含这些字段的新索引,这些字段被聚合到更粗的时间桶中。你可以以极低的成本存储数月或数年的历史数据,并保持相同的查询性能。

例如,假设你每五秒收集一次 CPU 消耗数据,并将其存储在热节点上。你可以将 older 数据汇总或压缩为每日平均 CPU 消耗,或每周间隔减少 10%,而不是将 older 数据移动到只读温节点。

你可以通过三种方式使用索引汇总:

  1. 使用索引汇总 API 对未主动摄取的索引(如已滚动的索引)执行按需索引汇总作业。例如,你可以执行索引汇总操作,将五分钟间隔收集的数据减少为每周平均趋势分析。

  2. 使用 UDB-SX Dashboards UI 创建按定义计划运行的索引汇总作业。你还可以设置为在主动摄取时滚动索引。例如,你可以持续将 Logstash 索引从五秒间隔汇总为一小时间隔。

  3. 将索引汇总作业指定为 ISM 操作,以完成索引管理。这允许你在某些事件(如滚动、索引年龄达到某点、索引变为只读等)后汇总索引。你还可以让滚动和索引汇总作业顺序运行,其中滚动首先将当前索引移动到温节点,然后索引汇总作业在热节点上创建具有最小化数据的新索引。

创建索引汇总作业

首先,在 UDB-SX Dashboards 中选择 索引管理。 选择 汇总作业,然后选择 创建汇总作业

步骤 1:设置索引

  1. 作业名称和描述 部分,为索引汇总作业指定唯一名称和可选描述。

  2. 索引 部分,选择源索引和目标索引。源索引是你想要汇总的索引。源索引保持不变,索引汇总作业创建一个新索引,称为目标索引。目标索引是保存索引汇总结果的地方。对于目标索引,你可以输入新索引的名称,或选择现有索引。

  3. 选择 下一步

创建索引汇总作业后,你无法更改索引选择。

步骤 2:定义聚合和指标

选择要汇总的属性,包括聚合(术语和直方图)和指标(avg、sum、max、min 和 value count)。确保不要添加大量高粒度属性,因为这样你不会节省太多空间。

例如,考虑一个城市和城市内人口统计数据的数据集。你可以基于城市进行聚合,并将城市内的人口统计数据指定为指标。 你选择属性的顺序至关重要。城市后跟人口统计数据与人口统计数据后跟城市不同。

  1. 时间聚合 部分,选择时间戳字段。在 固定日历 间隔类型之间选择,并指定间隔和时区。索引汇总作业使用此信息为时间戳字段创建日期直方图。

  2. (可选)为每个字段添加额外的聚合。你可以为所有字段类型选择术语聚合,仅对数字字段选择直方图聚合。

  3. (可选)为每个字段添加额外的指标。你可以在 全部最小最大总和平均值计数 之间选择。

  4. 选择 下一步

步骤 3:指定调度

指定一个调度计划,以便在摄取时滚动索引。默认情况下,索引汇总作业处于启用状态。

  1. 指定数据是否连续。

  2. 对于汇总执行频率,选择 按固定间隔定义 并指定 汇总间隔 和时间单位,或 按 cron 表达式定义 并添加 cron 表达式以选择间隔。要了解如何定义 cron 表达式,请参见 警报

  3. 指定每个执行过程的页数。较大的数字意味着执行速度更快,内存成本更高。

  4. (可选)为汇总执行添加延迟。这是作业等待数据摄取以适应任何处理时间的时长。例如,如果你将此值设置为 10 分钟,一个在下午 2 点执行以汇总下午 1 点到下午 2 点数据的索引汇总将在下午 2:10 开始。

  5. 选择 下一步

步骤 4:查看并创建

查看你的配置并选择 创建

步骤 5:搜索目标索引

你可以使用标准 _search API 搜索目标索引。确保查询与目标索引的约束匹配。例如,如果你没有在某个字段上设置术语聚合,你不会收到该术语聚合的结果。如果你没有设置最大聚合,你不会收到最大聚合的结果。

你无法访问目标索引中数据的内部结构,因为插件会在后台自动重写查询以适应目标索引。这是为了确保你可以对源索引和目标索引使用相同的查询。

要查询目标索引,将 size 设置为 0:

GET target_index/_search
{
  "size": 0,
  "query": {
    "match_all": {}
  },
  "aggs": {
    "avg_cpu": {
      "avg": {
        "field": "cpu_usage"
      }
    }
  }
}

考虑一个场景,你从下午 1 点到下午 9 点以小时间隔收集汇总数据,从下午 7 点到下午 11 点以分钟间隔收集实时数据。如果你在同一个查询中对这些数据执行聚合,对于下午 7 点到下午 9 点,你会看到汇总数据和实时数据的重叠,因为它们在聚合中被计算了两次。

示例演练

此演练使用 UDB-SX Dashboards 电子商务订单数据示例。要添加该示例数据,登录到 UDB-SX Dashboards,选择 主页 点击 插入示例数据。在 电子商务订单示例模块下,点击 添加数据

然后运行搜索:

GET opensearch_dashboards_sample_data_ecommerce/_search

示例响应

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 4675,
      "relation": "eq"
    },
    "max_score": 1,
    "hits": [
      {
        "_index": "opensearch_dashboards_sample_data_ecommerce",
        "_id": "yIHxvpoBk4dTBbWd0TWp",
        "_score": 1,
        "_source": {
          "category": [
            "Men's Clothing"
          ],
          "currency": "EUR",
          "customer_first_name": "Eddie",
          "customer_full_name": "Eddie Underwood",
          "customer_gender": "MALE",
          "customer_id": 38,
          "customer_last_name": "Underwood",
          "customer_phone": "",
          "day_of_week": "Monday",
          "day_of_week_i": 0,
          "email": "eddie@underwood-family.zzz",
          "manufacturer": [
            "Elitelligence",
            "Oceanavigations"
          ],
          "order_date": "2025-12-08T09:28:48+00:00",
          "order_id": 584677,
          "products": [
            {
              "base_price": 11.99,
              "discount_percentage": 0,
              "quantity": 1,
              "manufacturer": "Elitelligence",
              "tax_amount": 0,
              "product_id": 6283,
              "category": "Men's Clothing",
              "sku": "ZO0549605496",
              "taxless_price": 11.99,
              "unit_discount_amount": 0,
              "min_price": 6.35,
              "_id": "sold_product_584677_6283",
              "discount_amount": 0,
              "created_on": "2016-12-26T09:28:48+00:00",
              "product_name": "Basic T-shirt - dark blue/white",
              "price": 11.99,
              "taxful_price": 11.99,
              "base_unit_price": 11.99
            },
            {
              "base_price": 24.99,
              "discount_percentage": 0,
              "quantity": 1,
              "manufacturer": "Oceanavigations",
              "tax_amount": 0,
              "product_id": 19400,
              "category": "Men's Clothing",
              "sku": "ZO0299602996",
              "taxless_price": 24.99,
              "unit_discount_amount": 0,
              "min_price": 11.75,
              "_id": "sold_product_584677_19400",
              "discount_amount": 0,
              "created_on": "2016-12-26T09:28:48+00:00",
              "product_name": "Sweatshirt - grey multicolor",
              "price": 24.99,
              "taxful_price": 24.99,
              "base_unit_price": 24.99
            }
          ],
          "sku": [
            "ZO0549605496",
            "ZO0299602996"
          ],
          "taxful_total_price": 36.98,
          "taxless_total_price": 36.98,
          "total_quantity": 2,
          "total_unique_products": 2,
          "type": "order",
          "user": "eddie",
          "geoip": {
            "country_iso_code": "EG",
            "location": {
              "lon": 31.3,
              "lat": 30.1
            },
            "region_name": "Cairo Governorate",
            "continent_name": "Africa",
            "city_name": "Cairo"
          },
          "event": {
            "dataset": "sample_ecommerce"
          }
        }
      },
      ...
    ]
  }
}

创建索引汇总作业。 此示例选择 order_datecustomer_gendergeoip.city_namegeoip.region_nameday_of_week 字段,并将它们汇总到目标索引 example_rollup

PUT _plugins/_rollup/jobs/example
{
  "rollup": {
    "enabled": true,
    "schedule": {
      "interval": {
        "period": 1,
        "unit": "Minutes",
        "start_time": 1602100553
      }
    },
    "last_updated_time": 1602100553,
    "description": "汇总示例电子商务数据的示例策略",
    "source_index": "opensearch_dashboards_sample_data_ecommerce",
    "target_index": "example_rollup",
    "page_size": 1000,
    "delay": 0,
    "continuous": false,
    "dimensions": [
      {
        "date_histogram": {
          "source_field": "order_date",
          "fixed_interval": "60m",
          "timezone": "America/Los_Angeles"
        }
      },
      {
        "terms": {
          "source_field": "customer_gender"
        }
      },
      {
        "terms": {
          "source_field": "geoip.city_name"
        }
      },
      {
        "terms": {
          "source_field": "geoip.region_name"
        }
      },
      {
        "terms": {
          "source_field": "day_of_week"
        }
      }
    ],
    "metrics": [
      {
        "source_field": "taxless_total_price",
        "metrics": [
          {
            "avg": {}
          },
          {
            "sum": {}
          },
          {
            "max": {}
          },
          {
            "min": {}
          },
          {
            "value_count": {}
          }
        ]
      },
      {
        "source_field": "total_quantity",
        "metrics": [
          {
            "avg": {}
          },
          {
            "max": {}
          }
        ]
      }
    ]
  }
}

你可以查询 example_rollup 索引中在汇总作业中设置的字段的术语聚合。 你会收到与原始 opensearch_dashboards_sample_data_ecommerce 源索引相同的响应:

POST example_rollup/_search
{
  "size": 0,
  "query": {
    "bool": {
      "must": {"term": { "geoip.region_name": "California" } }
    }
  },
  "aggregations": {
    "daily_numbers": {
      "terms": {
        "field": "day_of_week"
      },
      "aggs": {
        "per_city": {
          "terms": {
            "field": "geoip.city_name"
          },
          "aggs": {
            "average quantity": {
               "avg": {
                  "field": "total_quantity"
                }
              }
            }
          },
          "total_revenue": {
            "sum": {
              "field": "taxless_total_price"
          }
        }
      }
    }
  }
}

示例响应

{
  "took" : 14,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 281,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "daily_numbers" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "Friday",
          "doc_count" : 59,
          "total_revenue" : {
            "value" : 4858.84375
          },
          "per_city" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "Los Angeles",
                "doc_count" : 59,
                "average quantity" : {
                  "value" : 2.305084745762712
                }
              }
            ]
          }
        },
        {
          "key" : "Saturday",
          "doc_count" : 46,
          "total_revenue" : {
            "value" : 3547.203125
          },
          "per_city" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "Los Angeles",
                "doc_count" : 46,
                "average quantity" : {
                  "value" : 2.260869565217391
                }
              }
            ]
          }
        },
        {
          "key" : "Tuesday",
          "doc_count" : 45,
          "total_revenue" : {
            "value" : 3983.28125
          },
          "per_city" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "Los Angeles",
                "doc_count" : 45,
                "average quantity" : {
                  "value" : 2.2888888888888888
                }
              }
            ]
          }
        },
        {
          "key" : "Sunday",
          "doc_count" : 44,
          "total_revenue" : {
            "value" : 3308.1640625
          },
          "per_city" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "Los Angeles",
                "doc_count" : 44,
                "average quantity" : {
                  "value" : 2.090909090909091
                }
              }
            ]
          }
        },
        {
          "key" : "Thursday",
          "doc_count" : 40,
          "total_revenue" : {
            "value" : 2876.125
          },
          "per_city" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "Los Angeles",
                "doc_count" : 40,
                "average quantity" : {
                  "value" : 2.3
                }
              }
            ]
          }
        },
        {
          "key" : "Monday",
          "doc_count" : 38,
          "total_revenue" : {
            "value" : 2673.453125
          },
          "per_city" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "Los Angeles",
                "doc_count" : 38,
                "average quantity" : {
                  "value" : 2.1578947368421053
                }
              }
            ]
          }
        },
        {
          "key" : "Wednesday",
          "doc_count" : 38,
          "total_revenue" : {
            "value" : 3202.453125
          },
          "per_city" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "Los Angeles",
                "doc_count" : 38,
                "average quantity" : {
                  "value" : 2.236842105263158
                }
              }
            ]
          }
        }
      ]
    }
  }
}

doc_count 字段

存储桶聚合中的 doc_count 字段包含每个存储桶中收集的文档数量。在计算存储桶的 doc_count 时,文档数量会增加每个摘要文档中预聚合文档的数量。从汇总搜索返回的 doc_count 表示源索引中匹配文档的总数。无论你是搜索源索引还是汇总目标索引,每个存储桶的文档数量都是相同的。

查询字符串查询

为了利用查询 DSL 中更短、更容易编写的字符串,你可以在汇总索引中使用查询字符串 来简化搜索查询。要使用查询字符串,在你的汇总搜索请求中添加以下字段:

"query": {
      "query_string": {
          "query": "field_name:field_value"
      }
  }

以下示例使用带有 * 通配符运算符的查询字符串在名为 my_server_logs_rollup 的汇总索引中搜索:

GET my_server_logs_rollup/_search
{
  "size": 0,
  "query": {
      "query_string": {
          "query": "email* OR inventory",
          "default_field": "service_name"
      }
  },  
  
  "aggs": {
    "service_name": {
      "terms": {
        "field": "service_name"
      },
      "aggs": {
        "region": {
          "terms": {
            "field": "region"
          },
          "aggs": {
            "average quantity": {
               "avg": {
                  "field": "cpu_usage"
                }
              }
            }
          }
        }
      }
    }
}

有关查询字符串查询参数的更多信息,请参见查询字符串查询

动态目标索引

在 ISM 汇总中,target_index 字段可能包含一个在每次汇总索引时编译的模板。例如,如果你将 target_index 字段指定为 rollup_ndx-{{ctx.source_index}} 源索引 log-000001 将汇总到目标索引 rollup_ndx-log-000001。这允许你将数据汇总到多个基于时间的索引,每个源索引创建一个汇总作业。

{{ctx.source_index}} 中的 source_index 参数不能包含通配符。

搜索多个汇总索引

当数据汇总到多个目标索引时,你可以在所有汇总索引上运行一次搜索。要搜索具有相同汇总的多个目标索引,请将索引名称指定为逗号分隔列表或通配符模式。例如,如果 target_indexrollup_ndx-{{ctx.source_index}} 并且源索引以 log 开头,请指定 rollup_ndx-log* 模式。或者,要搜索汇总的 log-000001 和 log-000002 索引,请指定 rollup_ndx-log-000001,rollup_ndx-log-000002 列表。

你不能用同一个查询搜索汇总索引和非汇总索引的混合。

示例

以下示例演示了 doc_count 字段、动态索引名称以及使用相同汇总搜索多个汇总索引。

步骤 1: 为 ISM 添加索引模板以管理由 log 别名的索引的滚动:

PUT _index_template/ism_rollover
{
  "index_patterns": ["log*"],
  "template": {
   "settings": {
    "plugins.index_state_management.rollover_alias": "log"
   }
 }
}

步骤 2: 设置 ISM 滚动策略,在上传一个文档后滚动任何名称以 log* 开头的索引,然后汇总各个后备索引。目标索引名称通过在前缀添加字符串 rollup_ndx- 到源索引名称动态生成。

PUT _plugins/_ism/policies/rollover_policy 
{ 
  "policy": { 
    "description": "示例滚动策略。", 
    "default_state": "rollover", 
    "states": [ 
      { 
        "name": "rollover", 
        "actions": [ 
          { 
            "rollover": { 
              "min_doc_count": 1 
            } 
          } 
        ], 
        "transitions": [ 
          { 
            "state_name": "rp" 
          } 
        ] 
      }, 
      { 
        "name": "rp", 
        "actions": [
          { 
            "rollup": { 
              "ism_rollup": { 
                "target_index": "rollup_ndx-{{ctx.source_index}}", 
                "description": "示例汇总作业", 
                "page_size": 200, 
                "dimensions": [ 
                  { 
                    "date_histogram": { 
                      "source_field": "ts", 
                      "fixed_interval": "60m", 
                      "timezone": "America/Los_Angeles" 
                    } 
                  }, 
                  { 
                    "terms": { 
                      "source_field": "message.keyword" 
                    } 
                  } 
                ], 
                "metrics": [ 
                  { 
                    "source_field": "msg_size", 
                    "metrics": [ 
                      { 
                        "sum": {} 
                      } 
                    ]
                  } 
                ]
              } 
            } 
          } 
        ], 
        "transitions": [] 
      } 
    ], 
    "ism_template": { 
      "index_patterns": ["log*"], 
      "priority": 100 
    } 
  } 
}

步骤 3: 创建名为 log-000001 的索引,并为其设置别名 log

PUT log-000001
{
  "aliases": {
    "log": {
      "is_write_index": true
    }
  }
}

步骤 4: 将四个文档索引到上面创建的索引中。其中两个文档的消息为 “Success”,两个文档的消息为 “Error”。

POST log/_doc?refresh=true 
{ 
  "ts" : "2022-08-26T09:28:48-04:00", 
  "message": "Success", 
  "msg_size": 10 
}
POST log/_doc?refresh=true 
{ 
  "ts" : "2022-08-26T10:06:25-04:00", 
  "message": "Error", 
  "msg_size": 20 
}
POST log/_doc?refresh=true 
{ 
  "ts" : "2022-08-26T10:23:54-04:00", 
  "message": "Error", 
  "msg_size": 30 
}
POST log/_doc?refresh=true 
{ 
  "ts" : "2022-08-26T10:53:41-04:00", 
  "message": "Success", 
  "msg_size": 40 
}

一旦你索引了第一个文档,滚动操作就会执行。此操作创建索引 log-000002,并将 rollover_policy 附加到它。然后执行汇总操作,创建汇总索引 rollup_ndx-log-000001

要监控滚动和汇总索引创建的状态,你可以使用 ISM 解释 API:GET _plugins/_ism/explain

步骤 5: 搜索汇总索引。

GET rollup_ndx-log-*/_search
{
  "size": 0,
  "query": {
    "match_all": {}
  },
  "aggregations": {
    "message_numbers": {
      "terms": {
        "field": "message.keyword"
      },
      "aggs": {
        "per_message": {
          "terms": {
            "field": "message.keyword"
          },
          "aggregations": {
            "sum_message": {
              "sum": {
                "field": "msg_size"
              }
            }
          }
        }
      }
    }
  }
}

响应包含两个存储桶,“Error” 和 “Success”,每个存储桶的文档计数为 2:

{
  "took" : 30,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 4,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "message_numbers" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "Success",
          "doc_count" : 2,
          "per_message" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "Success",
                "doc_count" : 2,
                "sum_message" : {
                  "value" : 50.0
                }
              }
            ]
          }
        },
        {
          "key" : "Error",
          "doc_count" : 2,
          "per_message" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "Error",
                "doc_count" : 2,
                "sum_message" : {
                  "value" : 50.0
                }
              }
            ]
          }
        }
      ]
    }
  }
}

索引编解码器注意事项

有关索引编解码器的注意事项,请参见 索引编解码器