统计聚合

更新时间:
复制 MD 格式

使用 Tablestore Go SDK 对多元索引查询结果计算指标或按条件分组。

前提条件

安装Tablestore Go SDK并初始化客户端。

功能说明

统计聚合在查询结果上计算平均值、最大值、最小值、总和、计数、去重计数、百分位数或 TopRows,也可以按字段、范围、日期、地理位置、过滤条件和组合键分组。用于指标聚合或按字段值、范围、直方图等方式分组的字段必须启用排序与统计聚合;GroupByFilter 中的过滤条件遵循对应查询类型的字段要求。

重要
  • 去重计数、百分位数和字段值分组采用近似计算。去重计数小于 1 万时结果接近精确值,达到 1 亿时误差约为 2%。百分位越接近两端通常越准确,例如 P1 或 P99 通常比 P50 更准确。字段值分组并行计算时可能存在少量误差。

  • 多个统计聚合可以组合使用。聚合数量多或嵌套层级深时会增加请求复杂度并影响响应速度。嵌套层级限制请参见多元索引使用限制

以下示例查询多元索引中的全部数据,计算价格的最小值、最大值、总和、平均值、非空值数量、类别去重数和 P50,并按类别分组。

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)

参数说明

查询请求

名称

类型

说明

TableName(必选)

string

数据表名称。

IndexName(必选)

string

多元索引名称。

SearchQuery(必选)

search.SearchQuery

查询条件、指标聚合和分组配置。

ColumnsToGet(可选)

*tablestore.ColumnsToGet

返回列配置,仅 TopRowsAggregation 返回分组内行时生效。未设置时只返回主键列。

RoutingValues(可选)

[]*tablestore.PrimaryKey

自定义路由字段对应的主键值列表。未配置自定义路由时无需设置。

TimeoutMs(可选)

*int32

请求级超时时间,单位为毫秒。

查询配置

名称

类型

说明

SetQuery(必选)

search.Query

设置查询条件。

SetOffset(可选)

int32

设置本次查询的起始位置,默认值为 0。使用 Offset 翻页时,Offset + Limit 不能超过 100000。

SetLimit(可选)

int32

设置本次查询返回的最大行数,默认值为 10,最大值为 100。设置为 0 时不返回具体行。

SetCollapse(可选)

*search.Collapse

设置结果折叠。配置方法请参见折叠(去重)

SetSort(可选)

*search.Sort

设置返回结果的排序方式。配置方法请参见排序和翻页

SetGetTotalCount(可选)

bool

是否统计匹配总行数,默认值为 false。

SetToken(可选)

[]byte

设置上一次响应返回的 NextToken,以继续读取后续数据。调用该方法会清除 Sort,因为 Token 已包含上一页的排序条件。使用 Token 翻页时不能设置 Offset。

SetSearchFilter(可选)

*search.SearchFilter

对查询结果执行后过滤。配置方法请参见查询后过滤

Aggregation(可选)

...search.Aggregation

设置统计聚合。配置方法请参见统计聚合

GroupBy(可选)

...search.GroupBy

设置分组。配置方法请参见统计聚合

指标聚合

名称

类型

说明

AvgAggregation(可选)

search.AvgAggregation

计算平均值。

MaxAggregation(可选)

search.MaxAggregation

计算最大值。

MinAggregation(可选)

search.MinAggregation

计算最小值。

SumAggregation(可选)

search.SumAggregation

计算总和。

CountAggregation(可选)

search.CountAggregation

计算非空值数量。

DistinctCountAggregation(可选)

search.DistinctCountAggregation

计算不同值数量。

PercentilesAggregation(可选)

search.PercentilesAggregation

计算百分位数。

TopRowsAggregation(可选)

search.TopRowsAggregation

返回分组内的前若干行。

MinAggregation、MaxAggregation、AvgAggregation 和 SumAggregation

名称

类型

说明

AggName(必选)

string

聚合名称,在读取结果时作为标识。

Field(必选)

string

聚合字段名称。Min、Max 和 Avg 支持 Long、Double 和 Date,Sum 支持 Long 和 Double。

MissingValue(可选)

interface{}

字段缺失时参与计算的替代值。未设置时忽略字段缺失的行。

CountAggregation 和 DistinctCountAggregation

名称

类型

说明

AggName(必选)

string

聚合名称。

Field(必选)

string

统计字段名称,支持 Long、Double、Boolean、Keyword、Date、IP 和 Geo-point。Count 不统计字段缺失的行。

MissingValue(可选)

interface{}

仅 DistinctCountAggregation 支持,字段缺失时使用该值参与去重统计。未设置时忽略字段缺失的行。

CountAggregation 统计指定字段的非空值行数,适合稀疏列。若要统计查询匹配总行数,请调用 SetGetTotalCount(true) 并读取 SearchResponse.TotalCount;若要统计多元索引全部行,查询条件使用 MatchAllQuery。

PercentilesAggregation

Go SDK 1.7.0 及以上版本支持 PercentilesAggregation。

名称

类型

说明

AggName(必选)

string

聚合名称。

Field(必选)

string

聚合字段名称,支持 Long、Double 和 Date。

Percents(必选)

[]float64

要计算的百分位数,例如 25、50、90 和 99。

MissingValue(可选)

interface{}

字段缺失时参与计算的替代值。未设置时忽略字段缺失的行。

TopRowsAggregation

TopRowsAggregation 作为分组的子聚合使用。Go SDK 1.7.0 及以上版本支持该功能。

名称

类型

说明

AggName(必选)

string

聚合名称。

Limit(可选)

*int32

每个分组内返回的最大行数,默认值为 1。

Sort(可选)

*search.Sort

返回行的排序方式。

返回哪些属性列由 SearchRequest.ColumnsToGet 控制。要直接从多元索引返回属性列,创建多元索引时必须存储相应字段;未设置返回列时只返回主键列。

分组

名称

类型

说明

GroupByField(可选)

search.GroupByField

按字段值分组。

GroupByRange(可选)

search.GroupByRange

按数值范围分组。

GroupByGeoDistance(可选)

search.GroupByGeoDistance

按地理距离分组。

GroupByFilter(可选)

search.GroupByFilter

按过滤条件分组。

GroupByHistogram(可选)

search.GroupByHistogram

按固定数值间隔分组。

GroupByDateHistogram(可选)

search.GroupByDateHistogram

按日期或时间间隔分组。

GroupByGeoGrid(可选)

search.GroupByGeoGrid

按 GeoHash 网格分组。

GroupByComposite(可选)

search.GroupByComposite

按多个字段的组合键分组并支持翻页。

GroupByField

名称

类型

说明

AggName(必选)

string

分组名称。

Field(必选)

string

分组字段名称,支持 Long、Double、Boolean、Keyword、Date 和 IP。

Sz(可选)

*int32

返回的分组数量,默认值为 10,最大值为 2000。

Sorters(可选)

[]search.GroupBySorter

分组排序方式,多个规则按列表顺序生效。默认按分组内行数降序排列。

SubAggList(可选)

[]search.Aggregation

子聚合列表。

SubGroupByList(可选)

[]search.GroupBy

子分组列表。

分组排序

分组支持以下排序类型:

  • GroupKeyGroupBySort:按分组值的字典序升序或降序排列。

  • RowCountGroupBySort:按分组内行数升序或降序排列,默认按此类型降序排列。

  • SubAggGroupBySort:按指定子指标聚合的结果升序或降序排列。

GroupByRange

名称

类型

说明

AggName(必选)

string

分组名称。

Field(必选)

string

分组字段名称,支持 Long 和 Double。

RangeList(必选)

[]search.Range

左闭右开的分组范围列表。边界可使用 search.NegInf 和 search.Inf。

SubAggList(可选)

[]search.Aggregation

子聚合列表。

SubGroupByList(可选)

[]search.GroupBy

子分组列表。

GroupByGeoDistance

名称

类型

说明

AggName(必选)

string

分组名称。

Field(必选)

string

分组字段名称,仅支持 Geo-point。

Origin(必选)

search.GeoPoint

中心坐标,纬度在前、经度在后。纬度范围为 [-90,+90],经度范围为 [-180,+180]。

RangeList(必选)

[]search.Range

左闭右开的距离范围列表,单位为米。边界可使用 search.NegInf 和 search.Inf。

SubAggList(可选)

[]search.Aggregation

子聚合列表。

SubGroupByList(可选)

[]search.GroupBy

子分组列表。

GroupByFilter

名称

类型

说明

AggName(必选)

string

分组名称。

Queries(必选)

[]search.Query

过滤条件列表,结果顺序与查询条件顺序一致。

SubAggList(可选)

[]search.Aggregation

子聚合列表。

SubGroupByList(可选)

[]search.GroupBy

子分组列表。

GroupByHistogram

名称

类型

说明

GroupByName(必选)

string

分组名称。

Field(必选)

string

分组字段名称,支持 Long 和 Double。

Interval(必选)

interface{}

数值分组间隔。

FieldRange(可选)

model.FiledRange

参与分组的字段值范围。配置后,(Max - Min) / Interval 不能超过 2000。

Missing(可选)

interface{}

字段缺失时使用的分组值。未设置时忽略字段缺失的行。

MinDocCount(可选)

*int64

返回分组需要包含的最少行数。

Sorters(可选)

[]search.GroupBySorter

分组排序方式。

SubAggList(可选)

[]search.Aggregation

子聚合列表。

SubGroupByList(可选)

[]search.GroupBy

子分组列表。

GroupByDateHistogram

Go SDK 1.7.10 及以上版本支持 GroupByDateHistogram。

名称

类型

说明

GroupByName(必选)

string

分组名称。

Field(必选)

string

分组字段名称,仅支持 Date。

Interval(必选)

model.DateTimeValue

日期或时间分组间隔,由数值和时间单位组成。

FieldRange(可选)

model.FiledRange

参与分组的字段值范围。配置后,(Max - Min) / Interval 不能超过 2000。

Missing(可选)

interface{}

字段缺失时使用的日期分组值。未设置时忽略字段缺失的行。

MinDocCount(可选)

*int64

返回分组需要包含的最少行数。

TimeZone(可选)

*string

格式为 +hh:mm 或 -hh:mm,例如 +08:00。Date 字段格式未包含时区时,可设置该参数避免聚合结果产生时差。

Sorters(可选)

[]search.GroupBySorter

分组排序方式。

SubAggList(可选)

[]search.Aggregation

子聚合列表。

SubGroupByList(可选)

[]search.GroupBy

子分组列表。

GroupByGeoGrid

Go SDK 1.7.12 及以上版本支持 GroupByGeoGrid。

名称

类型

说明

GroupByName(必选)

string

分组名称。

Field(必选)

string

Geo-point 字段名称。

Precision(必选)

model.GeoHashPrecision

GeoHash 网格精度。枚举序号越大,网格越小。

Size(必选)

int64

返回的网格分组数量。

SubAggList(可选)

[]search.Aggregation

子聚合列表。

SubGroupByList(可选)

[]search.GroupBy

子分组列表。

GroupByComposite

Go SDK 1.7.15 及以上版本支持 GroupByComposite。

名称

类型

说明

GroupByName(必选)

string

分组名称。

SourceGroupByList(必选)

[]search.GroupBy

多字段分组源,最多包含 32 个字段,仅支持 GroupByField、GroupByHistogram 和 GroupByDateHistogram。GroupByField 源只使用名称、字段和排序;GroupByHistogram 源只使用名称、字段、间隔和排序;GroupByDateHistogram 源还可使用 TimeZone。源只支持按分组值排序,默认降序;字段值不存在时,对应键返回 null。

Size(可选)

*int32

本次返回的组合键数量,默认值为 10,最大值为 2000。不能与 SuggestedSize 同时设置。

SuggestedSize(可选)

*int32

面向 Spark、Presto 等计算引擎高吞吐场景的软限制。可设置为 -1 或大于服务端限制的值,实际返回数量为 min(SuggestedSize, 服务端分组限制, 总分组数)。不能与 Size 同时设置。

NextToken(可选)

*string

上一页分组结果返回的翻页凭证。

SubAggList(可选)

[]search.Aggregation

子聚合列表。

SubGroupByList(可选)

[]search.GroupBy

子分组列表。GroupByComposite 本身不能作为其他分组的子分组。

返回值

SearchResponse.AggregationResults 按聚合名称读取指标结果,从 SearchResponse.GroupByResults 按分组名称读取分组结果。

指标聚合结果

名称

类型

说明

Avg、Max、Min、Sum

Value float64

分别调用 AggregationResults.Avg、Max、Min 或 Sum 并传入聚合名称,读取返回对象的 Value。Avg、Max 和 Min 可调用 HasValue 判断结果是否包含有效值。

Count、DistinctCount

Value int64

分别调用 AggregationResults.Count 或 DistinctCount 并传入聚合名称,读取返回对象的 Value。

Percentiles

PercentilesAggregationItems []search.PercentilesAggregationItem

调用 AggregationResults.Percentiles 并传入聚合名称。每个结果项的 Key 为百分位数,Value 为对应值。

TopRows

Value []model.Row

调用 AggregationResults.TopRows 并传入聚合名称,读取返回对象的 Value。

分组结果

名称

类型

说明

GroupByField

[]search.GroupByFieldResultItem

调用 GroupByResults.GroupByField 获取结果。每项包含 Key、RowCount、SubAggregations 和 SubGroupBys。

GroupByRange

[]search.GroupByRangeResultItem

调用 GroupByResults.GroupByRange 获取结果。每项包含 From、To、RowCount、SubAggregations 和 SubGroupBys。

GroupByGeoDistance

[]search.GroupByGeoDistanceResultItem

调用 GroupByResults.GroupByGeoDistance 获取结果。每项包含距离范围 From 和 To、RowCount、SubAggregations 和 SubGroupBys。

GroupByFilter

[]search.GroupByFilterResultItem

调用 GroupByResults.GroupByFilter 获取结果。结果顺序与 Queries 顺序一致,每项包含 RowCount、SubAggregations 和 SubGroupBys。

GroupByHistogram

[]search.GroupByHistogramItem

调用 GroupByResults.GroupByHistogram 获取结果。每项的 Key 为分组值,Value 为分组内行数,并包含 SubAggregations 和 SubGroupBys。

GroupByDateHistogram

[]search.GroupByDateHistogramItem

调用 GroupByResults.GroupByDateHistogram 获取结果。每项包含毫秒时间戳 Timestamp、RowCount、SubAggregations 和 SubGroupBys。

GroupByGeoGrid

[]search.GroupByGeoGridResultItem

调用 GroupByResults.GroupByGeoGrid 获取结果。每项包含 GeoHash Key、网格边界 GeoGrid、RowCount、SubAggregations 和 SubGroupBys。

GroupByComposite

[]search.GroupByCompositeResultItem

调用 GroupByResults.GroupByComposite 获取结果。SourceGroupByNames 表示键顺序;每项的 Keys 与其一一对应,并包含 RowCount、SubAggregations 和 SubGroupBys。NextToken 为下一页凭证。

场景示例

使用子聚合和子分组

以下示例按类别分组,在每个类别中计算最高价格,并继续按状态分组。

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)
}

使用多字段分组并翻页

GroupByComposite 以扁平组合键返回多字段分组结果,并通过 NextToken 连续读取后续分组。

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
    }
}

按范围、距离和过滤条件分组

以下示例在同一个查询中按价格范围、地理距离和过滤条件分别分组。

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)

生成数值和日期直方图

以下示例按固定价格间隔生成数值直方图,并按月生成日期直方图。

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)

按地理网格分组

以下示例按约 39 km × 19 km 的 GeoHash 网格统计地理位置字段。

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)

获取分组内的行

以下示例按类别分组,并返回每个类别中价格最高的一行。

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)
}

多字段分组方式对比

按多个字段分组时,可以嵌套多个 GroupByField,也可以使用 GroupByComposite。根据返回结构、排序和是否需要翻页选择。

方式

特点

嵌套 GroupByField

按父子层级返回,每层最多返回 2000 个分组;不支持分组翻页;支持按分组值、行数或子聚合值排序,并支持子聚合。

GroupByComposite

以扁平组合键返回,最多包含 32 个字段;每页最多返回 2000 个分组并支持通过 NextToken 翻页;每个分组源仅支持按分组值排序,默认降序。Date 字段的分组键以时间戳字符串返回。