使用 Tablestore Python SDK 可对多元索引查询结果执行指标聚合和分组统计。
前提条件
安装Tablestore Python SDK并初始化客户端。
统计聚合功能需要使用 5.2.1 及以上版本,建议使用最新版本的 SDK。
功能说明
统计聚合基于多元索引查询的匹配结果计算指标或生成分组。将指标聚合对象添加到 SearchQuery.aggs,将分组对象添加到 SearchQuery.group_bys;同一请求中的 name 必须唯一,用于从响应中识别结果。只获取统计结果时,可将 limit 设置为 0。
|
功能 |
说明 |
|
Min、Max、Sum、Avg |
计算最小值、最大值、总和和平均值。 |
|
Count、DistinctCount |
统计字段非空值行数和不同值数量。 |
|
Percentiles |
计算一个或多个百分位值。 |
|
TopRows |
作为子聚合返回每个分组内排序靠前的行。 |
|
GroupByField、GroupByComposite |
按单个字段值或多个字段组合分组。 |
|
GroupByRange、GroupByGeoDistance、GroupByFilter |
按数值范围、地理距离或过滤条件分组。 |
|
GroupByHistogram、GroupByDateHistogram、GroupByGeoGrid |
生成数值直方图、日期直方图或 GeoHash 网格分组。 |
用于统计聚合的多元索引字段必须启用排序与统计聚合。不同聚合和分组支持的字段类型不同。同一层级最多配置 5 个分组。去重行数、百分位数和字段值分组采用近似计算;聚合数量多或嵌套层级深会增加请求复杂度并影响响应速度。
以下示例对 price 字段计算最小值、最大值和平均值,并按 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)
参数说明
查询请求
search 方法包含以下参数。
|
名称 |
类型 |
说明 |
|
table_name(必选) |
|
数据表名称。 |
|
index_name(必选) |
|
多元索引名称。 |
|
search_query(必选) |
|
查询条件和统计聚合配置。 |
|
columns_to_get(可选) |
|
返回列配置。未设置时只返回主键列。 |
|
routing_keys(可选) |
|
自定义路由字段对应的主键值列表。未配置自定义路由时无需设置。 |
|
timeout_s(可选) |
|
请求级超时时间,单位为秒。未设置时使用客户端默认超时时间。 |
查询配置
search_query 的类型为 SearchQuery,包含以下与统计聚合相关的参数。
|
名称 |
类型 |
说明 |
|
query(必选) |
|
统计范围对应的查询条件。统计全部数据时设置为 |
|
aggs(可选) |
|
指标聚合列表,可组合多个不同名称的聚合。 |
|
group_bys(可选) |
|
分组列表,可组合多个不同名称的分组。 |
|
limit(可选) |
|
查询返回行数。只获取统计结果时设置为 |
指标聚合
以下各对象添加到 search_query.aggs。field 为聚合字段,name 为结果名称,missing_value 表示字段缺失时用于参与计算的值;未设置 missing_value 时忽略缺少该字段的行。
Min、Max 和 Avg
|
名称 |
类型 |
说明 |
|
field(必选) |
|
聚合字段,支持 |
|
missing_value(可选) |
|
字段缺失时参与计算的值。 |
|
name(可选) |
|
聚合名称,默认分别为 |
Sum
|
名称 |
类型 |
说明 |
|
field(必选) |
|
聚合字段,支持 |
|
missing_value(可选) |
|
字段缺失时用于求和的值。 |
|
name(可选) |
|
聚合名称,默认值为 |
Count
|
名称 |
类型 |
说明 |
|
field(必选) |
|
要统计非空值行数的字段,支持 |
|
name(可选) |
|
聚合名称,默认值为 |
DistinctCount
|
名称 |
类型 |
说明 |
|
field(必选) |
|
要统计不同值数量的字段,支持 |
|
missing_value(可选) |
|
字段缺失时参与去重统计的值。 |
|
name(可选) |
|
聚合名称,默认值为 |
Percentiles
|
名称 |
类型 |
说明 |
|
field(必选) |
|
聚合字段,支持 |
|
percentiles_list(必选) |
|
要计算的百分位列表,例如 |
|
missing_value(可选) |
|
字段缺失时参与计算的值。 |
|
name(可选) |
|
聚合名称,默认值为 |
TopRows
|
名称 |
类型 |
说明 |
|
limit(必选) |
|
每个分组内最多返回的行数。 |
|
sort(必选) |
|
分组内行的排序方式。 |
|
name(可选) |
|
聚合名称,默认值为 |
DistinctCount 为近似统计:不同值少于 10,000 时结果接近精确值;达到 1 亿时误差约为 2%。Percentiles 也为近似统计,较极端的百分位通常比中位数更准确。TopRows 仅作为分组的子聚合使用。
分组
以下各对象添加到 search_query.group_bys。sub_aggs 和 sub_group_bys 可分别对每个分组继续执行子指标聚合和子分组。
GroupByField
|
名称 |
类型 |
说明 |
|
field_name(必选) |
|
分组字段,支持 |
|
size(可选) |
|
返回分组数,默认值为 |
|
group_by_sort(可选) |
|
分组排序规则。默认按行数降序,支持 |
|
sub_aggs(可选) |
|
子指标聚合。 |
|
sub_group_bys(可选) |
|
子分组。 |
|
name(可选) |
|
分组名称,默认值为 |
GroupByComposite
|
名称 |
类型 |
说明 |
|
sources(必选) |
|
多字段分组源,最多 32 个。支持 |
|
size(可选) |
|
返回分组数,默认值为 |
|
next_token(可选) |
|
下一页分组凭证。首次请求不设置。 |
|
suggested_size(可选) |
|
高吞吐计算场景的软限制,不能与 |
|
sub_aggs(可选) |
|
子指标聚合。 |
|
sub_group_bys(可选) |
|
子分组。 |
|
name(可选) |
|
分组名称,默认值为 |
GroupByRange
|
名称 |
类型 |
说明 |
|
field_name(必选) |
|
分组字段,支持 |
|
ranges(必选) |
|
左闭右开范围列表,例如 |
|
sub_aggs(可选) |
|
子指标聚合。 |
|
sub_group_bys(可选) |
|
子分组。 |
|
name(可选) |
|
分组名称,默认值为 |
GroupByGeoDistance
|
名称 |
类型 |
说明 |
|
field_name(必选) |
|
|
|
origin(必选) |
|
中心点,构造参数依次为纬度和经度。 |
|
ranges(必选) |
|
距离范围列表,单位为米,采用左闭右开区间。 |
|
sub_aggs(可选) |
|
子指标聚合。 |
|
sub_group_bys(可选) |
|
子分组。 |
|
name(可选) |
|
分组名称,默认值为 |
GroupByFilter
|
名称 |
类型 |
说明 |
|
filters(必选) |
|
过滤条件列表,结果顺序与条件顺序一致。 |
|
sub_aggs(可选) |
|
子指标聚合。 |
|
sub_group_bys(可选) |
|
子分组。 |
|
name(可选) |
|
分组名称,默认值为 |
GroupByHistogram
|
名称 |
类型 |
说明 |
|
field_name(必选) |
|
分组字段,支持 |
|
interval(必选) |
|
数值直方图间隔。 |
|
field_range(必选) |
|
统计范围。 |
|
missing_value(可选) |
|
字段缺失时参与直方图统计的值。 |
|
min_doc_count(可选) |
|
分组内最少行数,行数不足的桶不返回。 |
|
group_by_sort(可选) |
|
分组排序规则。 |
|
sub_aggs(可选) |
|
子指标聚合。 |
|
sub_group_bys(可选) |
|
子分组。 |
|
name(可选) |
|
分组名称,默认值为 |
GroupByDateHistogram
|
名称 |
类型 |
说明 |
|
field_name(必选) |
|
|
|
interval(必选) |
|
日期或时间间隔,由数值和 |
|
field_range(必选) |
|
统计范围。虽然 Python 构造方法允许省略,但服务端要求必须设置。 |
|
missing(可选) |
|
字段缺失时参与日期直方图统计的日期值。 |
|
min_doc_count(可选) |
|
分组内最少行数,行数不足的桶不返回。 |
|
time_zone(可选) |
|
时区,格式为 |
|
group_by_sort(可选) |
|
分组排序规则。 |
|
offset(可选) |
|
桶边界相对默认起点的偏移量。 |
|
sub_aggs(可选) |
|
子指标聚合。 |
|
sub_group_bys(可选) |
|
子分组。 |
|
name(可选) |
|
分组名称,默认值为 |
GroupByGeoGrid
|
名称 |
类型 |
说明 |
|
field_name(必选) |
|
|
|
precision(必选) |
|
GeoHash 网格精度,枚举序号越大,网格越小。 |
|
size(可选) |
|
返回的网格分组数。 |
|
sub_aggs(可选) |
|
子指标聚合。 |
|
sub_group_bys(可选) |
|
子分组。 |
|
name(可选) |
|
分组名称,默认值为 |
GroupByComposite 需要使用 Python SDK 6.4.4 及以上版本。分组结果较多时,设置 size 并使用返回结果的 next_token 翻页,直到凭证为空。
返回列
columns_to_get 的类型为 ColumnsToGet,包含以下参数。
|
名称 |
类型 |
说明 |
|
column_names(可选) |
|
要返回的属性列名称。仅 |
|
return_type(可选) |
|
返回列模式。 |
返回值
search 方法返回 SearchResponse。核心字段如下。
|
字段 |
类型 |
说明 |
|
rows |
|
本次查询返回的行数据,数量不超过 |
|
next_token |
|
下一页凭证。值为空时表示没有更多数据。 |
|
total_count |
|
匹配行数,取决于 |
|
is_all_succeed |
|
是否已成功查询全部索引分区。值为 |
|
agg_results |
|
指标聚合结果。未配置 |
|
group_by_results |
|
分组结果。未配置 |
|
search_hits |
|
查询命中结果,包含行数据、相关性得分和高亮结果等扩展信息。 |
agg_results 中每项通过 name 和 value 标识聚合及其值;group_by_results 中每项通过 name 和 items 返回各分组键、行数、子聚合和子分组。GroupByComposite 结果还包含 source_group_by_names 和用于继续读取的 next_token;每个分组的 keys 为字符串列表,与 sources 顺序一致,字段值为空时对应位置为 None。
兼容 Tuple 返回格式
Tablestore Python SDK 5.2.0 开始将查询接口的返回值由 Tuple 调整为响应对象,5.1.0 及以下版本直接返回 Tuple。5.2.1 及以上版本可调用 SearchResponse.v1_response() 获取与旧版本兼容的 Tuple。新代码建议直接访问 SearchResponse 的属性,避免返回字段扩展后解包数量不匹配。
(
rows,
next_token,
total_count,
is_all_succeed,
agg_results,
group_by_results,
search_hits,
) = response.v1_response()
场景示例
使用多字段分组并翻页
以下示例按 category 和 price 组合分组,每次返回两个分组。
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)
生成日期直方图和地理网格
以下示例按天生成日期直方图,并按约 39 km × 19 km 的 GeoHash 网格划分地理位置。
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)