> ## Documentation Index
> Fetch the complete documentation index at: https://docs.honeycomb.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Applying Temporal Aggregation Functions

> Apply temporal aggregation functions to your metrics queries and customize how Honeycomb aligns raw data into time steps for precise analysis.

export const HnyIcon = ({alias, path, size = 16, iconColor}) => {
  const iconMap = {
    "home": "house.svg",
    "marker": "caretFilledDown.svg",
    "show-marker-options": "chatTextLeft.svg",
    "download": "arrowLineDown.svg",
    "trace-waterfall": "trace.svg",
    "show-query-details": "listDashes.svg",
    "table": "table.svg",
    "log-lines": "logLines.svg",
    "chart": "chartLine.svg",
    "show-settings": "gear.svg",
    "add": "plus.svg",
    "remove": "delete.svg",
    "persist": "caretDown.svg",
    "close": "close.svg",
    "copy": "copy.svg",
    "zoom-in": "magnifyingGlassPlus.svg",
    "zoom-out": "magnifyingGlassMinus.svg",
    "color-assignment": "drop.svg",
    "drag": "dots-six-vertical.svg",
    "drawer": "drawer.svg",
    "show-actions": "dotsThree.svg",
    "edit": "pencil.svg",
    "delete": "trash.svg",
    "move": "arrowsOutCardinal.svg",
    "show-legend": "circleInfo.svg",
    "usage-ok": "usageGood.svg",
    "usage-warning": "usageWarning.svg",
    "usage-danger": "usageDanger.svg",
    "open-query-builder": "query.svg",
    "home-menu": "house.svg",
    "query-menu": "query.svg",
    "boards-menu": "board.svg",
    "triggers-menu": "bell.svg",
    "slos-menu": "handshake.svg",
    "service-map-menu": "serviceMap.svg",
    "history-menu": "clockCounterClockwise.svg",
    "manage-data-menu": "cube.svg",
    "usage-menu": "usageGood.svg",
    "show-details": "dotsThreeVertical.svg",
    "resize-handle": "board-panel-resize-handle.png",
    "standard-dataset": "cube.svg",
    "trace-dataset": "cubeChat.svg",
    "all-datasets": "linkedSquares.svg",
    "share": "arrowBentRight.svg",
    "run-in-query-builder": "arrowSquareUpRight.svg",
    "link": "link.svg",
    "text": "text.svg",
    "receive": "arrowLineDown.svg",
    "process": "lightning.svg",
    "sample": "drop.svg",
    "send": "arrowLineUp.svg",
    "submit": "arrowUp.svg",
    "canvas-menu": "sparkle.svg",
    "canvas": "sparkle.svg",
    "private": "lockKey.svg",
    "shared": "people.svg",
    "expand": "caretDown.svg",
    "previous": "caretLeft.svg",
    "next": "caretRight.svg"
  };
  const iconBasePath = "/_assets/icons/";
  const iconPath = path || (alias ? `${iconBasePath}${iconMap[alias]}` : undefined);
  return <span className="hny-icon" style={{
    display: "inline-block",
    width: `${size}px`,
    height: `${size}px`,
    maskImage: `url(${iconPath})`,
    maskSize: "contain",
    maskRepeat: "no-repeat",
    maskPosition: "center",
    WebkitMaskImage: `url(${iconPath})`,
    WebkitMaskSize: "contain",
    WebkitMaskRepeat: "no-repeat",
    WebkitMaskPosition: "center",
    backgroundColor: iconColor || "var(--hny-icon-color)",
    verticalAlign: "middle"
  }} />;
};

Control how Honeycomb aggregates your metrics over time by applying temporal aggregation functions directly in your queries.

## Introduction

Honeycomb automatically applies the appropriate temporal aggregation function for each metric based on its metadata, so most queries work out of the box without manual setup.

When the defaults do not match your expectations or you need more control, you can override them using Honeycomb's supported temporal aggregation functions.

## Default Behavior

OpenTelemetry defines several core metric types:

* **Gauge**: A single numeric value at a point in time, such as memory usage or temperature.
  Gauges represent a snapshot of a value at a single point in time.
  They are not counting up or down, so monotonicity does not apply.
  Similarly, gauges are not tracking change over time, so temporality is also not meaningful.

* **Sum**: A continuously increasing or fluctuating counter.
  Used to track totals like bytes sent or messages processed.
  Can be monotonic (only increases) or non-monotonic (can go up or down), and use either delta (change since last measurement) or cumulative (total since start) temporality.

* **Histogram**: A distribution of values collected over a time range, grouped into buckets.
  Useful for measuring things like request sizes or durations.
  Histogram buckets are counters under the hood, but they are not monotonic.
  This is because each bucket represents the count of values that fall within a specific range, so negative values do not make sense in this context.
  Histograms can be either delta or cumulative.

* **Exponential Histogram**: Like a histogram, but uses exponential bucket sizes for more efficient encoding of large ranges.
  Treated the same as histograms for querying purposes.

Because each metric type behaves differently over time, Honeycomb automatically selects the appropriate temporal aggregation function based on metadata:

| Data Type | Monotonic? | Temporality | Default Aggregation |
| --------- | ---------- | ----------- | ------------------- |
| Gauge     | N/A        | N/A         | `LAST()`            |
| Sum       | Yes        | Cumulative  | `INCREASE()`        |
| Sum       | No         | Cumulative  | `LAST()`            |
| Sum       | Any        | Delta       | `SUMMARIZE()`       |
| Histogram | N/A        | Cumulative  | `INCREASE()`        |
| Histogram | N/A        | Delta       | `SUMMARIZE()`       |

These defaults are our best guess at what you will typically want to see when you query that metric.
For example, gauges represent point-in-time values, so it makes sense to return the latest sample per time step.
Sums and histograms usually track change over time, so Honeycomb computes increases or totals.

For a detailed look at aggregation functions and metric types, visit [Temporal Aggregation Concepts](/investigate/query/temporal-aggregation/).

## When to Override Default Behavior

Although Honeycomb chooses an aggregation function based on the structure of the metric by default, you might want to manually apply a temporal aggregation function if:

* You want to control how data is bucketed across step boundaries
* You are debugging and want to see raw or step-aligned data
* You need a specific range for calculating `RATE()` or `INCREASE()`
* The automatic default is not suitable for your use case

For example, you may want to:

* Normalize counters by time to view a rate instead of a raw increase.
* Show the latest value in a gauge instead of an average.
* Total values across time steps to understand burst behavior.

## Manually Applying Temporal Aggregation Functions

To override default temporal aggregation behavior, create a [query-scoped calculated field](/investigate/query/build/calculated-fields/#choosing-the-scope), wrapping the target metric name inside a supported [temporal aggregation function](/investigate/query/temporal-aggregation/#supported-temporal-aggregation-functions).
For example, you can define a calculated field like `RATE(http.server.request.count)` to override the default and apply `RATE()` explicitly.

You can use this syntax in the **SELECT** clause or anywhere you reference a metric.

To learn more about the supported temporal aggregation functions, visit [Temporal Aggregation Concepts](/investigate/query/temporal-aggregation/#supported-temporal-aggregation-functions).

### Query Clauses and Temporal Aggregation

When you build a metrics query that includes temporal aggregation functions, you can use the full power of Honeycomb’s query clauses, including **SELECT**, **WHERE**, **GROUP BY**, **ORDER BY**, **LIMIT**, and **HAVING**.

Here is how each clause fits in:

* **SELECT** is where you apply aggregate functions to define what gets plotted on your chart.
* **GROUP BY** and **WHERE** can target both metric attributes (like `k8s.node.name` or `http.route`) and metric values.
  Filtering on metric values, such as **WHERE** `INCREASE(http.server.request.duration) &gt; 10000`, is fully supported and often useful.
  Grouping by raw metric values is more limited.
  For example, grouping by buckets of values requires wrapping metrics in calculated field expressions, which is not yet supported.
* **HAVING** lets you filter results after aggregation based on the aggregated values themselves.
  For example, you can exclude any group where the `RATE()` of a metric falls below a certain threshold.
* **ORDER BY** and **LIMIT** behave just as they do in other Honeycomb queries, letting you sort and trim the aggregated results.

To get aggregated trends over time, your query must include at least one aggregate function in the **SELECT** clause.
Without an aggregation, we default to `COUNT`, so the chart will return results that do not reflect anything meaningful for metrics.

### Using Temporal Aggregation Functions in Queries

To use temporal aggregation functions in queries, define a query-scoped calculated field in the Query Builder or include them in your API request.

<Tabs>
  <Tab title="Using the Honeycomb UI">
    To create a query with a temporal aggregation function:

    1. Select **Query** (<HnyIcon alias="query-menu" />) from the navigation menu.

    2. Select the `Metrics` dataset.

    3. Select the **SELECT** clause field, and choose **Define Calculated Field**.

    4. Enter a name for your calculated field, such as `my_rate`.

    5. In the editor, enter a formula that includes a temporal aggregation function, and select **Use in query**:

       ```js theme={}
       RATE($http.server.requests, 300)
       ```

       Use the `$` prefix to reference a raw metric.

       The second argument (`300`) is optional and sets the time window (in seconds) used to calculate the rate.
       To learn more, visit [Temporal Aggregation Concepts: Understanding the range\_interval\_seconds argument](/investigate/query/temporal-aggregation/#understanding-the-range_interval_seconds-argument).

    6. In the **SELECT** clause section, add your new field, and use `HEATMAP()` on the calculated field to produce a visualization:

       ```js theme={}
       HEATMAP(my_rate)
       ```

    7. Select **Run Query**.

    This will return a time-aligned heatmap showing how the rate of `http.server.requests` varies across series (such as hosts or pods) over 5-minute windows.
  </Tab>

  <Tab title="Using the Honeycomb API">
    To [define a metrics-based query via the Honeycomb API](/api/queries/create-a-query), include your calculated field in the `calculated_fields` section, and then reference it in `calculations` using a supported operator like `HEATMAP()`.

    Use `Metrics` as your `datasetSlug`.

    ```json theme={}
    {
      "time_range": 3600,
      "granularity": 60,
      "calculated_fields": [
        {
          "name": "my_rate",
          "expression": "RATE($http.server.requests, 300)"
        }
      ],
      "calculations": [
        {
          "op": "HEATMAP", 
          "column": "my_rate"
        }
      ]
    }
    ```
  </Tab>
</Tabs>

### Example Queries

These examples show how to override Honeycomb's default temporal aggregation behavior by applying temporal aggregation functions directly in a query-scoped calculated field.

Each example uses the Honeycomb Query Language to define queries and assumes you are working in the Query Builder or sending queries via the API.

#### Track Requests Per Second with `RATE()`

Calculate the per-second rate of `http.requests.total`, using a 60-second time window.
This smooths out spikes and normalizes throughput over time, regardless of the query's granularity.

Use this when you are interested in how frequently something happens rather than the total count.

* **Calculated Field**:
  `RATE($http.requests.total, 60)`

* **Query**:
  `VISUALIZE AVG(custom_rate)`

#### Combine `RATE()` with a Percentile Aggregation

Track the 99th percentile of the rate of `http.server.request.body.size`, using a 60-second time window.
Use the `RATE()`temporal aggregation function in a calculated field, and then apply `P99` in the aggregate clause.

Use this when you want to monitor high-percentile throughput of request body sizes, which is helpful for catching unusually large payloads.

* **Calculated Field**:
  `RATE($http.server.request.body.size, 60)`

* **Query**:
  `VISUALIZE P99(rate_body)`

#### Compare Request Sizes by Node

Compute the 99th percentile of request body size per Kubernetes node.

Use this when you want to compare the distribution of request sizes across the nodes or other dimensions.

* **Calculated field**:
  No calculated field is necessary because Honeycomb applies the appropriate default temporal aggregation function for this histogram field.

* **Query**:
  * `VISUALIZE P99(http.server.request.body.size)`
  * `GROUP BY k8s.node.name`

#### Get Total Requests for Delta Metrics

Use `SUMMARIZE()` to compute the total value of a delta metric in each time step.
Delta-style sums represent change between reports.
This function adds those values to get per-step totals.

* **Calculated Field**:
  `SUMMARIZE($http.requests.delta_count)`

* **Query**:
  `VISUALIZE SUM(total_requests)`

### Tips for Querying

Use these strategies to build effective queries with temporal aggregation functions:

* Always include an aggregate clause to trigger temporal aggregation.
* Use `GROUP BY` attributes, not raw metric fields.
* Use `range_interval_seconds` in `RATE()` and `INCREASE()` for smoother results.
* Validate results visually to confirm expected behavior.
