All Products
Search
Document Center

Tablestore:Aggregation

Last Updated:Aug 11, 2026

Use the Tablestore SDK for Go to calculate metrics or group search index query results.

Prerequisites

Install the Tablestore Go SDK and initialize a client.

Description

Aggregation calculates averages, maximums, minimums, sums, counts, distinct counts, percentiles, or top rows over query results. Results can also be grouped by fields, ranges, dates, geographic locations, filters, or composite keys. Sorting and aggregation must be enabled for fields used in metric aggregations or field-, range-, or histogram-based grouping. Filters in GroupByFilter follow the field requirements of the corresponding query type.

Important
  • Distinct counts, percentiles, and field-value grouping use approximate calculations. A distinct count below 10,000 is close to the exact value, and the error is approximately 2% at 100 million. Percentiles closer to the ends, such as P1 and P99, are typically more accurate than P50. Field-value grouping may have a small error because it is calculated in parallel.

  • You can combine multiple aggregations. A large number of aggregations or deep nesting increases request complexity and response latency. For nesting limits, see Search index limits.

The following example queries all data in a search index, calculates the minimum, maximum, sum, average, non-null count, distinct category count, and P50 of prices, and groups the data by category.

searchQuery := search.NewSearchQuery().
    SetQuery(&search.MatchAllQuery{}).
    SetLimit(0).
    Aggregation(
        search.NewMinAggregation("min_price", "price"),
        search.NewMaxAggregation("max_price", "price"),
        search.NewSumAggregation("sum_price", "price"),
        search.NewAvgAggregation("avg_price", "price"),
        search.NewCountAggregation("price_count", "price"),
        search.NewDistinctCountAggregation("category_count", "category"),
        search.NewPercentilesAggregation("price_percentiles", "price").
            SetPercents([]float64{50}),
    ).
    GroupBy(search.NewGroupByField("category_group", "category").Size(10))

response, err := client.Search(&tablestore.SearchRequest{
    TableName:   "example_table",
    IndexName:   "example_index",
    SearchQuery: searchQuery,
})
if err != nil {
    log.Fatal(err)
}

minResult, err := response.AggregationResults.Min("min_price")
if err != nil {
    log.Fatal(err)
}
maxResult, err := response.AggregationResults.Max("max_price")
if err != nil {
    log.Fatal(err)
}
sumResult, err := response.AggregationResults.Sum("sum_price")
if err != nil {
    log.Fatal(err)
}
avg, err := response.AggregationResults.Avg("avg_price")
if err != nil {
    log.Fatal(err)
}
countResult, err := response.AggregationResults.Count("price_count")
if err != nil {
    log.Fatal(err)
}
distinctResult, err := response.AggregationResults.DistinctCount("category_count")
if err != nil {
    log.Fatal(err)
}
percentilesResult, err := response.AggregationResults.Percentiles("price_percentiles")
if err != nil {
    log.Fatal(err)
}
groups, err := response.GroupByResults.GroupByField("category_group")
if err != nil {
    log.Fatal(err)
}

fmt.Println(minResult.Value, maxResult.Value, sumResult.Value)
fmt.Println(avg.Value)
fmt.Println(countResult.Value, distinctResult.Value)
fmt.Println(percentilesResult.PercentilesAggregationItems)
fmt.Println(groups.Items)

Parameters

Query request

Name

Type

Description

TableName (required)

string

The name of the data table.

IndexName (required)

string

The name of the search index.

SearchQuery (required)

search.SearchQuery

The query condition, metric aggregations, and grouping configurations.

ColumnsToGet (optional)

*tablestore.ColumnsToGet

The return-column configuration. This parameter takes effect only when TopRowsAggregation returns rows within groups. If omitted, only primary key columns are returned.

RoutingValues (optional)

[]*tablestore.PrimaryKey

Primary key values for custom routing fields. Omit this parameter if custom routing is not configured.

TimeoutMs (optional)

*int32

The request timeout period in milliseconds.

Query configuration

Name

Type

Description

SetQuery (required)

search.Query

Specifies the query condition.

SetOffset (optional)

int32

Specifies the start position. Default value: 0. For offset-based pagination, Offset + Limit cannot exceed 100,000.

SetLimit (optional)

int32

Specifies the maximum number of rows to return. Default value: 10. Maximum value: 100. A value of 0 returns no rows.

SetCollapse (optional)

*search.Collapse

Collapses query results. For more information, see Collapse query results.

SetSort (optional)

*search.Sort

Specifies the result sort order. For more information, see Sort and paginate results.

SetGetTotalCount (optional)

bool

Specifies whether to count all matched rows. Default value: false.

SetToken (optional)

[]byte

Specifies the NextToken value returned by the previous response. This method clears Sort because the token contains the previous-page sort conditions. Do not specify Offset when you use token-based pagination.

SetSearchFilter (optional)

*search.SearchFilter

Applies a post-query filter. For more information, see Use post-query filters.

Aggregation (optional)

...search.Aggregation

Configures aggregations. For more information, see Aggregation.

GroupBy (optional)

...search.GroupBy

Configures grouping. For more information, see Aggregation.

Metric aggregations

Name

Type

Description

AvgAggregation (optional)

search.AvgAggregation

Calculates an average.

MaxAggregation (optional)

search.MaxAggregation

Calculates a maximum.

MinAggregation (optional)

search.MinAggregation

Calculates a minimum.

SumAggregation (optional)

search.SumAggregation

Calculates a sum.

CountAggregation (optional)

search.CountAggregation

Counts non-null values.

DistinctCountAggregation (optional)

search.DistinctCountAggregation

Counts distinct values.

PercentilesAggregation (optional)

search.PercentilesAggregation

Calculates percentiles.

TopRowsAggregation (optional)

search.TopRowsAggregation

Returns top rows within a group.

MinAggregation, MaxAggregation, AvgAggregation, and SumAggregation

Name

Type

Description

AggName (required)

string

The aggregation name, which identifies the result.

Field (required)

string

The aggregation field. Min, Max, and Avg support Long, Double, and Date fields. Sum supports Long and Double fields.

MissingValue (optional)

interface{}

The substitute value used when the field is missing. If this parameter is not specified, rows in which the field is missing are ignored.

CountAggregation and DistinctCountAggregation

Name

Type

Description

AggName (required)

string

The aggregation name.

Field (required)

string

The field to count. Long, Double, Boolean, Keyword, Date, IP, and Geo-point fields are supported. Count does not include rows in which the field is missing.

MissingValue (optional)

interface{}

Supported only by DistinctCountAggregation. The value is used for distinct counting when the field is missing. If this parameter is not specified, rows in which the field is missing are ignored.

CountAggregation counts rows in which the specified field is not null and is suitable for sparse columns. To count all rows matched by a query, call SetGetTotalCount(true) and read SearchResponse.TotalCount. To count all rows in a search index, use MatchAllQuery as the query condition.

PercentilesAggregation

PercentilesAggregation is supported by Tablestore SDK for Go 1.7.0 and later.

Name

Type

Description

AggName (required)

string

The aggregation name.

Field (required)

string

The aggregation field. Long, Double, and Date fields are supported.

Percents (required)

[]float64

The percentiles to calculate, such as 25, 50, 90, and 99.

MissingValue (optional)

interface{}

The substitute value used when the field is missing. If this parameter is not specified, rows in which the field is missing are ignored.

TopRowsAggregation

Use TopRowsAggregation as a subaggregation of a group. This feature is supported by Tablestore SDK for Go 1.7.0 and later.

Name

Type

Description

AggName (required)

string

The aggregation name.

Limit (optional)

*int32

The maximum number of rows returned within each group. Default value: 1.

Sort (optional)

*search.Sort

The sort order of returned rows.

SearchRequest.ColumnsToGet controls which attribute columns are returned. To return attribute columns directly from the search index, store the corresponding fields when you create the index. If return columns are not specified, only primary key columns are returned.

Grouping

Name

Type

Description

GroupByField (optional)

search.GroupByField

Groups by field value.

GroupByRange (optional)

search.GroupByRange

Groups by numeric range.

GroupByGeoDistance (optional)

search.GroupByGeoDistance

Groups by geographic distance.

GroupByFilter (optional)

search.GroupByFilter

Groups by filter.

GroupByHistogram (optional)

search.GroupByHistogram

Groups by fixed numeric intervals.

GroupByDateHistogram (optional)

search.GroupByDateHistogram

Groups by date or time intervals.

GroupByGeoGrid (optional)

search.GroupByGeoGrid

Groups by GeoHash grid.

GroupByComposite (optional)

search.GroupByComposite

Groups by a composite key of multiple fields and supports pagination.

GroupByField

Name

Type

Description

AggName (required)

string

The group name.

Field (required)

string

The group field. Long, Double, Boolean, Keyword, Date, and IP fields are supported.

Sz (optional)

*int32

The number of groups to return. Default value: 10. Maximum value: 2,000.

Sorters (optional)

[]search.GroupBySorter

The group sort order. Multiple sorters take effect in list order. By default, groups are sorted by row count in descending order.

SubAggList (optional)

[]search.Aggregation

Subaggregations.

SubGroupByList (optional)

[]search.GroupBy

Subgroups.

Group sorting

The following group sort types are supported:

  • GroupKeyGroupBySort: Sorts group keys in ascending or descending lexical order.

  • RowCountGroupBySort: Sorts by group row count in ascending or descending order. Descending row-count order is the default.

  • SubAggGroupBySort: Sorts by the result of the specified subaggregation in ascending or descending order.

GroupByRange

Name

Type

Description

AggName (required)

string

The group name.

Field (required)

string

The group field. Long and Double fields are supported.

RangeList (required)

[]search.Range

Left-closed, right-open group ranges. Bounds can use search.NegInf and search.Inf.

SubAggList (optional)

[]search.Aggregation

Subaggregations.

SubGroupByList (optional)

[]search.GroupBy

Subgroups.

GroupByGeoDistance

Name

Type

Description

AggName (required)

string

The group name.

Field (required)

string

The group field. Only Geo-point fields are supported.

Origin (required)

search.GeoPoint

The center coordinate in latitude-longitude order. Latitude ranges from -90 to +90, and longitude ranges from -180 to +180.

RangeList (required)

[]search.Range

Left-closed, right-open distance ranges in meters. Bounds can use search.NegInf and search.Inf.

SubAggList (optional)

[]search.Aggregation

Subaggregations.

SubGroupByList (optional)

[]search.GroupBy

Subgroups.

GroupByFilter

Name

Type

Description

AggName (required)

string

The group name.

Queries (required)

[]search.Query

The filters. Result order matches query-condition order.

SubAggList (optional)

[]search.Aggregation

Subaggregations.

SubGroupByList (optional)

[]search.GroupBy

Subgroups.

GroupByHistogram

Name

Type

Description

GroupByName (required)

string

The group name.

Field (required)

string

The group field. Long and Double fields are supported.

Interval (required)

interface{}

The numeric group interval.

FieldRange (optional)

model.FiledRange

The field-value range included in grouping. If configured, (Max - Min) / Interval cannot exceed 2,000.

Missing (optional)

interface{}

The group value used when the field is missing. If this parameter is not specified, rows in which the field is missing are ignored.

MinDocCount (optional)

*int64

The minimum number of rows required for a returned group.

Sorters (optional)

[]search.GroupBySorter

The group sort order.

SubAggList (optional)

[]search.Aggregation

Subaggregations.

SubGroupByList (optional)

[]search.GroupBy

Subgroups.

GroupByDateHistogram

GroupByDateHistogram is supported by Tablestore SDK for Go 1.7.10 and later.

Name

Type

Description

GroupByName (required)

string

The group name.

Field (required)

string

The group field. Only Date fields are supported.

Interval (required)

model.DateTimeValue

The date or time interval, consisting of a value and a time unit.

FieldRange (optional)

model.FiledRange

The field-value range included in grouping. If configured, (Max - Min) / Interval cannot exceed 2,000.

Missing (optional)

interface{}

The date group value used when the field is missing. If this parameter is not specified, rows in which the field is missing are ignored.

MinDocCount (optional)

*int64

The minimum number of rows required for a returned group.

TimeZone (optional)

*string

Use the +hh:mm or -hh:mm format, such as +08:00. If the Date field format does not contain a time zone, set this parameter to avoid a time offset in aggregation results.

Sorters (optional)

[]search.GroupBySorter

The group sort order.

SubAggList (optional)

[]search.Aggregation

Subaggregations.

SubGroupByList (optional)

[]search.GroupBy

Subgroups.

GroupByGeoGrid

GroupByGeoGrid is supported by Tablestore SDK for Go 1.7.12 and later.

Name

Type

Description

GroupByName (required)

string

The group name.

Field (required)

string

The Geo-point field.

Precision (required)

model.GeoHashPrecision

The GeoHash grid precision. A larger enum ordinal represents a smaller grid.

Size (required)

int64

The number of grid groups to return.

SubAggList (optional)

[]search.Aggregation

Subaggregations.

SubGroupByList (optional)

[]search.GroupBy

Subgroups.

GroupByComposite

GroupByComposite is supported by Tablestore SDK for Go 1.7.15 and later.

Name

Type

Description

GroupByName (required)

string

The group name.

SourceGroupByList (required)

[]search.GroupBy

The composite group sources. Up to 32 fields are supported. Valid source types are GroupByField, GroupByHistogram, and GroupByDateHistogram. A GroupByField source uses only its name, field, and sorters. A GroupByHistogram source uses only its name, field, interval, and sorters. A GroupByDateHistogram source can also use TimeZone. Sources support only group-key sorting, in descending order by default. If a field value does not exist, the corresponding key is null.

Size (optional)

*int32

The number of composite keys to return. Default value: 10. Maximum value: 2,000. Do not specify this parameter together with SuggestedSize.

SuggestedSize (optional)

*int32

A soft limit for high-throughput scenarios such as Spark and Presto. You can specify -1 or a value above the server limit. The actual number returned is min(SuggestedSize, server group limit, total groups). Do not specify this parameter together with Size.

NextToken (optional)

*string

The pagination token returned by the previous group result.

SubAggList (optional)

[]search.Aggregation

Subaggregations.

SubGroupByList (optional)

[]search.GroupBy

Subgroups. GroupByComposite itself cannot be used as a subgroup of another group.

Response

Read metric results by aggregation name from SearchResponse.AggregationResults and grouping results by group name from SearchResponse.GroupByResults.

Metric aggregation results

Name

Type

Description

Avg、Max、Min、Sum

Value float64

Call AggregationResults.Avg, Max, Min, or Sum with the aggregation name and read Value from the returned object. For Avg, Max, and Min, call HasValue to determine whether the result contains a valid value.

Count、DistinctCount

Value int64

Call AggregationResults.Count or DistinctCount with the aggregation name and read Value from the returned object.

Percentiles

PercentilesAggregationItems []search.PercentilesAggregationItem

Call AggregationResults.Percentiles with the aggregation name. In each item, Key is the percentile and Value is the corresponding value.

TopRows

Value []model.Row

Call AggregationResults.TopRows with the aggregation name and read Value from the returned object.

Grouping results

Name

Type

Description

GroupByField

[]search.GroupByFieldResultItem

Call GroupByResults.GroupByField. Each item contains Key, RowCount, SubAggregations, and SubGroupBys.

GroupByRange

[]search.GroupByRangeResultItem

Call GroupByResults.GroupByRange. Each item contains From, To, RowCount, SubAggregations, and SubGroupBys.

GroupByGeoDistance

[]search.GroupByGeoDistanceResultItem

Call GroupByResults.GroupByGeoDistance. Each item contains the distance bounds From and To, RowCount, SubAggregations, and SubGroupBys.

GroupByFilter

[]search.GroupByFilterResultItem

Call GroupByResults.GroupByFilter. Result order matches Queries. Each item contains RowCount, SubAggregations, and SubGroupBys.

GroupByHistogram

[]search.GroupByHistogramItem

Call GroupByResults.GroupByHistogram. In each item, Key is the bucket value and Value is the row count. Each item also contains SubAggregations and SubGroupBys.

GroupByDateHistogram

[]search.GroupByDateHistogramItem

Call GroupByResults.GroupByDateHistogram. Each item contains the millisecond timestamp Timestamp, RowCount, SubAggregations, and SubGroupBys.

GroupByGeoGrid

[]search.GroupByGeoGridResultItem

Call GroupByResults.GroupByGeoGrid. Each item contains the GeoHash Key, GeoGrid bounds, RowCount, SubAggregations, and SubGroupBys.

GroupByComposite

[]search.GroupByCompositeResultItem

Call GroupByResults.GroupByComposite. SourceGroupByNames specifies the key order. Keys in each item correspond to that order. Each item also contains RowCount, SubAggregations, and SubGroupBys. NextToken is the token for the next page.

Examples

Use subaggregations and subgroups

The following example groups rows by category, calculates the maximum price in each category, and further groups the rows by status.

groupBy := search.NewGroupByField("category_group", "category").
    Size(10).
    SubAggregation(search.NewMaxAggregation("max_price", "price")).
    SubGroupBy(search.NewGroupByField("status_group", "status").Size(10))

searchQuery := search.NewSearchQuery().
    SetQuery(&search.MatchAllQuery{}).
    SetLimit(0).
    GroupBy(groupBy)
response, err := client.Search(&tablestore.SearchRequest{
    TableName:   "example_table",
    IndexName:   "example_index",
    SearchQuery: searchQuery,
})
if err != nil {
    log.Fatal(err)
}

result, err := response.GroupByResults.GroupByField("category_group")
if err != nil {
    log.Fatal(err)
}
for _, item := range result.Items {
    maxPrice, err := item.SubAggregations.Max("max_price")
    if err != nil {
        log.Fatal(err)
    }
    statuses, err := item.SubGroupBys.GroupByField("status_group")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(item.Key, maxPrice.Value, statuses.Items)
}

Group by multiple fields and paginate results

GroupByComposite returns multi-field grouping results as flat composite keys and uses NextToken to read subsequent groups.

composite := search.NewGroupByComposite("category_status_group").
    SourceGroupBys(
        search.NewGroupByField("category", "category"),
        search.NewGroupByField("status", "status"),
    ).
    SetSize(100)

var nextToken *string
for {
    if nextToken != nil {
        composite.SetNextToken(nextToken)
    }
    searchQuery := search.NewSearchQuery().
        SetQuery(&search.MatchAllQuery{}).
        SetLimit(0).
        GroupBy(composite)
    response, err := client.Search(&tablestore.SearchRequest{
        TableName:   "example_table",
        IndexName:   "example_index",
        SearchQuery: searchQuery,
    })
    if err != nil {
        log.Fatal(err)
    }

    result, err := response.GroupByResults.GroupByComposite(
        "category_status_group",
    )
    if err != nil {
        log.Fatal(err)
    }
    for _, item := range result.Items {
        fmt.Println(item.Keys, item.RowCount)
    }

    nextToken = result.NextToken
    if nextToken == nil || *nextToken == "" {
        break
    }
}

Group by range, distance, and filter

The following example groups results by price range, geographic distance, and filter in the same query.

priceRanges := search.NewGroupByRange("price_ranges", "price").
    Range(0, 200).
    Range(200, 500)
distanceRanges := search.NewGroupByGeoDistance(
    "distance_ranges",
    "location",
    search.GeoPoint{Lat: 30.2741, Lon: 120.1551},
).
    Range(0, 100000).
    Range(100000, 1500000)
categoryFilters := search.NewGroupByFilter("category_filters").
    Query(&search.TermQuery{FieldName: "category", Term: "book-go"}).
    Query(&search.TermQuery{FieldName: "category", Term: "game"})

searchQuery := search.NewSearchQuery().
    SetQuery(&search.MatchAllQuery{}).
    SetLimit(0).
    GroupBy(priceRanges, distanceRanges, categoryFilters)
response, err := client.Search(&tablestore.SearchRequest{
    TableName:   "example_table",
    IndexName:   "example_index",
    SearchQuery: searchQuery,
})
if err != nil {
    log.Fatal(err)
}

priceResult, err := response.GroupByResults.GroupByRange("price_ranges")
if err != nil {
    log.Fatal(err)
}
distanceResult, err := response.GroupByResults.GroupByGeoDistance(
    "distance_ranges",
)
if err != nil {
    log.Fatal(err)
}
filterResult, err := response.GroupByResults.GroupByFilter("category_filters")
if err != nil {
    log.Fatal(err)
}
fmt.Println(priceResult.Items)
fmt.Println(distanceResult.Items)
fmt.Println(filterResult.Items)

Generate numeric and date histograms

The following example generates a numeric histogram by using fixed price intervals and a monthly date histogram.

groupKeyAscending := []search.GroupBySorter{
    &search.GroupKeyGroupBySort{Order: search.SortOrder_ASC.Enum()},
}
priceHistogram := search.NewGroupByHistogram("price_histogram", "price").
    SetInterval(int64(200)).
    SetFiledRange(int64(0), int64(600)).
    SetMinDocCount(1).
    SetGroupBySorters(groupKeyAscending)
dateHistogram := search.NewGroupByDateHistogram(
    "date_histogram",
    "event_time",
).
    SetInterval(model.DateTimeValue{
        Value: proto.Int32(1),
        Unit:  model.DateTimeUnit_MONTH.Enum(),
    }).
    SetFiledRange("2026-01-01T00:00:00", "2026-05-01T00:00:00").
    SetTimeZone("+08:00").
    SetMinDocCount(1).
    SetGroupBySorters(groupKeyAscending)

searchQuery := search.NewSearchQuery().
    SetQuery(&search.MatchAllQuery{}).
    SetLimit(0).
    GroupBy(priceHistogram, dateHistogram)
response, err := client.Search(&tablestore.SearchRequest{
    TableName:   "example_table",
    IndexName:   "example_index",
    SearchQuery: searchQuery,
})
if err != nil {
    log.Fatal(err)
}

priceResult, err := response.GroupByResults.GroupByHistogram("price_histogram")
if err != nil {
    log.Fatal(err)
}
dateResult, err := response.GroupByResults.GroupByDateHistogram("date_histogram")
if err != nil {
    log.Fatal(err)
}
fmt.Println(priceResult.Items)
fmt.Println(dateResult.Items)

Group by geographic grid

The following example groups a geographic field by GeoHash grids of approximately 39 km × 19 km.

searchQuery := search.NewSearchQuery().
    SetQuery(&search.MatchAllQuery{}).
    SetLimit(0).
    GroupBy(
        search.NewGroupByGeoGrid("geo_grid", "location").
            SetPrecision(model.GHP_39KM_19KM_4).
            SetSize(100),
    )
response, err := client.Search(&tablestore.SearchRequest{
    TableName:   "example_table",
    IndexName:   "example_index",
    SearchQuery: searchQuery,
})
if err != nil {
    log.Fatal(err)
}

result, err := response.GroupByResults.GroupByGeoGrid("geo_grid")
if err != nil {
    log.Fatal(err)
}
fmt.Println(result.Items)

Retrieve rows within groups

The following example groups rows by category and returns the row with the highest price in each category.

topRows := search.NewTopRowsAggregation("top_price").
    SetLimit(1).
    SetSort(&search.Sort{Sorters: []search.Sorter{
        &search.FieldSort{
            FieldName: "price",
            Order:     search.SortOrder_DESC.Enum(),
        },
    }})
groupBy := search.NewGroupByField("category_group", "category").
    Size(10).
    SubAggregation(topRows)
searchQuery := search.NewSearchQuery().
    SetQuery(&search.MatchAllQuery{}).
    SetLimit(0).
    GroupBy(groupBy)

response, err := client.Search(&tablestore.SearchRequest{
    TableName:   "example_table",
    IndexName:   "example_index",
    SearchQuery: searchQuery,
    ColumnsToGet: &tablestore.ColumnsToGet{
        Columns: []string{"category", "price"},
    },
})
if err != nil {
    log.Fatal(err)
}

groups, err := response.GroupByResults.GroupByField("category_group")
if err != nil {
    log.Fatal(err)
}
for _, item := range groups.Items {
    rows, err := item.SubAggregations.TopRows("top_price")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(item.Key, rows.Value)
}

Compare multi-field grouping methods

To group by multiple fields, nest multiple GroupByField values or use GroupByComposite. Choose based on the result structure, sorting requirements, and whether pagination is required.

Method

Characteristics

Nested GroupByField

Returns hierarchical parent-child groups. Each level returns up to 2,000 groups. Group pagination is not supported. Sorting by group key, row count, or subaggregation value and subaggregations are supported.

GroupByComposite

Returns flat composite keys for up to 32 fields. Each page returns up to 2,000 groups and supports NextToken pagination. Each source supports only group-key sorting and defaults to descending order. A Date group key is returned as a timestamp string.