Use Tablestore SDK for Python to perform metric aggregations and grouping on search index results.
Prerequisites
Install the Tablestore SDK for Python and initialize a client.
The aggregation feature requires SDK version 5.2.1 or later. We recommend that you use the latest SDK version.
Description
Aggregation calculates metrics or creates groups from search index query results. Add metric aggregation objects to SearchQuery.aggs and grouping objects to SearchQuery.group_bys. Each name in a request must be unique and identifies the corresponding response result. To retrieve only aggregation results, set limit to 0.
|
Feature |
Description |
|
Min, Max, Sum, Avg |
Calculate the minimum, maximum, sum, and average. |
|
Count, DistinctCount |
Count rows with non-empty field values and distinct field values. |
|
Percentiles |
Calculate one or more percentiles. |
|
TopRows |
Return top-sorted rows in each group as a sub-aggregation. |
|
GroupByField, GroupByComposite |
Group by one field value or a combination of fields. |
|
GroupByRange, GroupByGeoDistance, GroupByFilter |
Group by numeric range, geo distance, or filter conditions. |
|
GroupByHistogram, GroupByDateHistogram, GroupByGeoGrid |
Create numeric histograms, date histograms, or GeoHash grid groups. |
Search index fields used for aggregation must have sorting and aggregation enabled. Supported field types vary by aggregation and grouping type. You can configure up to five groupings at the same level. Distinct count, percentiles, and field grouping use approximate calculation. A large number of aggregations or deeply nested aggregations increases request complexity and latency.
The following example calculates the minimum, maximum, and average of price and groups rows by category.
search_query = SearchQuery(
MatchAllQuery(),
limit=0,
aggs=[
Min("price", name="min_price"),
Max("price", name="max_price"),
Avg("price", name="avg_price"),
],
group_bys=[
GroupByField("category", name="by_category"),
],
)
response = client.search(
"example_table",
"example_index",
search_query,
)
for result in response.agg_results:
print(result.name, result.value)
for result in response.group_by_results:
print(result.name, result.items)
Parameters
Search request
The search method contains the following parameters.
|
Name |
Type |
Description |
|
table_name (required) |
|
The name of the data table. |
|
index_name (required) |
|
The name of the search index. |
|
search_query (required) |
|
The query condition and common query configurations. |
|
columns_to_get (optional) |
|
The return column configuration. If this parameter is not specified, only primary key columns are returned. |
|
routing_keys (optional) |
|
The primary key values of custom routing fields. This parameter is not required if custom routing is not configured. |
|
timeout_s (optional) |
|
The request timeout in seconds. If this parameter is not specified, the client-level timeout is used. |
Query configuration
search_query is of the SearchQuery type and contains the following aggregation-related parameters.
|
Name |
Type |
Description |
|
query (required) |
|
The query condition that determines the aggregation scope. Use |
|
aggs (optional) |
|
The metric aggregation list. You can combine aggregations that have different names. |
|
group_bys (optional) |
|
The grouping list. You can combine groupings that have different names. |
|
limit (optional) |
|
The number of query rows to return. Set this parameter to |
Metric aggregations
Add the following objects to search_query.aggs. field is the aggregation field, name identifies the result, and missing_value is used when the field is missing. If missing_value is not specified, rows that lack the field are ignored.
Min, Max, and Avg
|
Name |
Type |
Description |
|
field (required) |
|
The aggregation field. Supported types: |
|
missing_value (optional) |
|
The value used when the field is missing. |
|
name (optional) |
|
The aggregation name. Defaults: |
Sum
|
Name |
Type |
Description |
|
field (required) |
|
The aggregation field. Supported types: |
|
missing_value (optional) |
|
The value used in the sum when the field is missing. |
|
name (optional) |
|
The aggregation name. Default value: |
Count
|
Name |
Type |
Description |
|
field (required) |
|
The field whose non-empty rows are counted. Supported types: |
|
name (optional) |
|
The aggregation name. Default value: |
DistinctCount
|
Name |
Type |
Description |
|
field (required) |
|
The field whose distinct values are counted. Supported types: |
|
missing_value (optional) |
|
The value included in the distinct count when the field is missing. |
|
name (optional) |
|
The aggregation name. Default value: |
Percentiles
|
Name |
Type |
Description |
|
field (required) |
|
The aggregation field. Supported types: |
|
percentiles_list (required) |
|
The percentiles to calculate, such as |
|
missing_value (optional) |
|
The value used when the field is missing. |
|
name (optional) |
|
The aggregation name. Default value: |
TopRows
|
Name |
Type |
Description |
|
limit (required) |
|
The maximum number of rows to return from each group. |
|
sort (required) |
|
The sort order of rows in each group. |
|
name (optional) |
|
The aggregation name. Default value: |
DistinctCount is approximate. Results are close to exact below 10,000 distinct values, and the error is about 2% at 100 million values. Percentiles is also approximate, and extreme percentiles are typically more accurate than the median. Use TopRows only as a sub-aggregation of a grouping.
Grouping
Add the following objects to search_query.group_bys. Use sub_aggs and sub_group_bys to perform metric sub-aggregations and subgrouping in each group.
GroupByField
|
Name |
Type |
Description |
|
field_name (required) |
|
The grouping field. Supported types: |
|
size (optional) |
|
The number of groups to return. Default value: |
|
group_by_sort (optional) |
|
The group sort rules. By default, groups are sorted by row count in descending order. |
|
sub_aggs (optional) |
|
The metric sub-aggregations. |
|
sub_group_bys (optional) |
|
The subgroupings. |
|
name (optional) |
|
The grouping name. Default value: |
GroupByComposite
|
Name |
Type |
Description |
|
sources (required) |
|
The multi-field grouping sources. You can specify up to 32 sources of the |
|
size (optional) |
|
The number of groups to return. Default value: |
|
next_token (optional) |
|
The token for the next page of groups. Omit it in the first request. |
|
suggested_size (optional) |
|
A soft limit for high-throughput compute scenarios. Do not specify it together with |
|
sub_aggs (optional) |
|
The metric sub-aggregations. |
|
sub_group_bys (optional) |
|
The subgroupings. |
|
name (optional) |
|
The grouping name. Default value: |
GroupByRange
|
Name |
Type |
Description |
|
field_name (required) |
|
The grouping field. Supported types: |
|
ranges (required) |
|
The left-closed, right-open ranges, such as |
|
sub_aggs (optional) |
|
The metric sub-aggregations. |
|
sub_group_bys (optional) |
|
The subgroupings. |
|
name (optional) |
|
The grouping name. Default value: |
GroupByGeoDistance
|
Name |
Type |
Description |
|
field_name (required) |
|
The |
|
origin (required) |
|
The center point. Constructor parameters are latitude followed by longitude. |
|
ranges (required) |
|
The distance ranges in meters. Each range is left-closed and right-open. |
|
sub_aggs (optional) |
|
The metric sub-aggregations. |
|
sub_group_bys (optional) |
|
The subgroupings. |
|
name (optional) |
|
The grouping name. Default value: |
GroupByFilter
|
Name |
Type |
Description |
|
filters (required) |
|
The filter conditions. Result order matches condition order. |
|
sub_aggs (optional) |
|
The metric sub-aggregations. |
|
sub_group_bys (optional) |
|
The subgroupings. |
|
name (optional) |
|
The grouping name. Default value: |
GroupByHistogram
|
Name |
Type |
Description |
|
field_name (required) |
|
The grouping field. Supported types: |
|
interval (required) |
|
The numeric histogram interval. |
|
field_range (required) |
|
The aggregation range. |
|
missing_value (optional) |
|
The value used in the histogram when the field is missing. |
|
min_doc_count (optional) |
|
The minimum row count for a bucket. Buckets with fewer rows are not returned. |
|
group_by_sort (optional) |
|
The group sort rules. |
|
sub_aggs (optional) |
|
The metric sub-aggregations. |
|
sub_group_bys (optional) |
|
The subgroupings. |
|
name (optional) |
|
The grouping name. Default value: |
GroupByDateHistogram
|
Name |
Type |
Description |
|
field_name (required) |
|
The |
|
interval (required) |
|
The date or time interval, composed of a value and |
|
field_range (required) |
|
The aggregation range. The server requires this parameter even though the Python constructor allows it to be omitted. |
|
missing (optional) |
|
The date value used in the histogram when the field is missing. |
|
min_doc_count (optional) |
|
The minimum row count for a bucket. Buckets with fewer rows are not returned. |
|
time_zone (optional) |
|
The time zone in |
|
group_by_sort (optional) |
|
The group sort rules. |
|
offset (optional) |
|
The bucket-boundary offset from the default origin. |
|
sub_aggs (optional) |
|
The metric sub-aggregations. |
|
sub_group_bys (optional) |
|
The subgroupings. |
|
name (optional) |
|
The grouping name. Default value: |
GroupByGeoGrid
|
Name |
Type |
Description |
|
field_name (required) |
|
The |
|
precision (required) |
|
The GeoHash grid precision. A higher enum number represents a smaller grid. |
|
size (optional) |
|
The number of grid groups to return. |
|
sub_aggs (optional) |
|
The metric sub-aggregations. |
|
sub_group_bys (optional) |
|
The subgroupings. |
|
name (optional) |
|
The grouping name. Default value: |
GroupByComposite requires Tablestore SDK for Python 6.4.4 or later. If many groups exist, specify size and paginate by using next_token from each result until the token is empty.
Return columns
columns_to_get is of the ColumnsToGet type and contains the following parameters.
|
Name |
Type |
Description |
|
column_names (optional) |
|
The names of attribute columns to return. Specify this parameter only when |
|
return_type (optional) |
|
The return column mode. |
Response
The search method returns SearchResponse. The following table describes the core fields.
|
Field |
Type |
Description |
|
rows |
|
The rows returned by the query. The number does not exceed |
|
next_token |
|
The token for the next page. An empty value indicates that no more data is available. |
|
total_count |
|
The number of matching rows. The value depends on |
|
is_all_succeed |
|
Indicates whether all index partitions were queried. If the value is |
|
agg_results |
|
The metric aggregation results. This field is empty if |
|
group_by_results |
|
The grouping results. This field is empty if |
|
search_hits |
|
The search hits, including extended information such as rows, relevance scores, and highlights. |
Each item in agg_results uses name and value to identify an aggregation and its value. Each item in group_by_results uses name and items to return group keys, row counts, sub-aggregations, and subgroupings. A GroupByComposite result also contains source_group_by_names and next_token for continued reads. The keys of each group is a string list aligned with sources; a missing field value is represented by None.
Tuple-compatible response
Starting from Tablestore SDK for Python 5.2.0, search APIs return response objects instead of tuples. Version 5.1.0 and earlier return tuples directly. In version 5.2.1 and later, you can call SearchResponse.v1_response() to obtain a tuple compatible with earlier versions. For new code, access SearchResponse attributes directly to avoid unpacking errors if response fields are extended.
(
rows,
next_token,
total_count,
is_all_succeed,
agg_results,
group_by_results,
search_hits,
) = response.v1_response()
Examples
Paginate a multi-field grouping
The following example groups by category and price and returns two groups per page.
sources = [
GroupByField("category", name="category_source"),
GroupByField("price", name="price_source"),
]
next_token = None
all_items = []
while True:
group_by = GroupByComposite(
sources,
size=2,
next_token=next_token,
name="by_category_and_price",
)
response = client.search(
"example_table",
"example_index",
SearchQuery(MatchAllQuery(), limit=0, group_bys=[group_by]),
)
result = response.group_by_results[0]
all_items.extend(result.items)
next_token = result.next_token
if not next_token:
break
for item in all_items:
print(item.keys, item.row_count)
Create a date histogram and geo grid
The following example creates a daily date histogram and groups locations into GeoHash grids of approximately 39 km by 19 km.
group_bys = [
GroupByDateHistogram(
"event_date",
DateTimeValue(1, DateTimeUnit.DAY),
field_range=FieldRange("2026-08-01", "2026-08-04"),
name="by_day",
),
GroupByGeoGrid(
"location",
GeoHashPrecision.GHP_39KM_19KM_4,
name="by_geo_grid",
),
]
response = client.search(
"example_table",
"example_index",
SearchQuery(MatchAllQuery(), limit=0, group_bys=group_bys),
)
for result in response.group_by_results:
print(result.name, result.items)