使用 Tablestore Java SDK 可對多元索引查詢結果計算指標或進行分組,支援長條圖、多層分組和擷取分組內的行。
前提條件
安裝Tablestore Java SDK並初始化用戶端。
功能說明
統計彙總在多元索引完成查詢後,對所有匹配行計算指標或進行分組。使用指標彙總可計算最小值、最大值、和、平均值、行數、去重行數和百分位元;使用分組可按欄位值、多個欄位、數值範圍、地理距離、過濾條件、數值間隔、日期間隔或地理網格統計行數。分組內還可以繼續添加子指標彙總或子分組。
|
類別 |
配置類型 |
功能 |
|
指標彙總 |
MinAggregation |
返回欄位的最小值,類似於 SQL 的 |
|
指標彙總 |
MaxAggregation |
返回欄位的最大值,類似於 SQL 的 |
|
指標彙總 |
SumAggregation |
返回數值欄位的和,類似於 SQL 的 |
|
指標彙總 |
AvgAggregation |
返回欄位的平均值,類似於 SQL 的 |
|
指標彙總 |
CountAggregation |
返回指定欄位存在值的行數,類似於 SQL 的 |
|
指標彙總 |
DistinctCountAggregation |
返回指定欄位不同值的數量,類似於 SQL 的 |
|
指標彙總 |
PercentilesAggregation |
返回指定欄位的一個或多個百分位元。 |
|
指標彙總 |
TopRowsAggregation |
在每個分組內按指定順序返回前若干行。 |
|
分組 |
GroupByField |
按單個欄位值分組。 |
|
分組 |
GroupByComposite |
按多個欄位分組,並通過翻頁憑證讀取後續分組。 |
|
分組 |
GroupByRange |
按數值範圍分組。 |
|
分組 |
GroupByGeoDistance |
按資料點與中心點之間的距離範圍分組。 |
|
分組 |
GroupByFilter |
按多個過濾條件分組。 |
|
分組 |
GroupByHistogram |
按固定數值間隔產生長條圖。 |
|
分組 |
GroupByDateHistogram |
按固定日期或時間間隔產生長條圖。 |
|
分組 |
GroupByGeoGrid |
按 GeoHash 網格分組。 |
用於統計彙總的多元索引欄位必須啟用排序與統計彙總。不同彙總類型支援的欄位類型不同,具體要求參見對應參數表。多元索引欄位類型及其與資料表欄位類型的映射關係請參見資料類型。
統計彙總基於查詢匹配結果計算。包含統計彙總的請求比僅查詢資料的請求複雜;如果不需要返回具體行,可將
limit設定為0。去重行數、百分位元和欄位值分組採用近似計算。去重行數小於 1 萬時結果接近精確值,達到 1 億時誤差約為 2%。百分位越接近兩端通常越準確,例如 P1 或 P99 通常比 P50 更準確。欄位值分組並行計算時可能存在少量誤差。
多個統計彙總可以組合使用。彙總數量多或嵌套層級深時會增加請求複雜度並影響響應速度。嵌套層級限制請參見多元索引使用限制。
調用 search 方法查詢資料,通過 SearchQuery.aggregationList 配置指標彙總,通過 SearchQuery.groupByList 配置分組。
SearchResponse search(SearchRequest request)
以下樣本查詢多元索引中的全部資料,計算價格的最小值、最大值、和、平均值、行數、去重類別數和 P50,並按類別分組。
SearchQuery searchQuery = SearchQuery.newBuilder()
.query(QueryBuilders.matchAll())
.limit(0)
.addAggregation(AggregationBuilders.min("min_price", "price"))
.addAggregation(AggregationBuilders.max("max_price", "price"))
.addAggregation(AggregationBuilders.sum("sum_price", "price"))
.addAggregation(AggregationBuilders.avg("avg_price", "price"))
.addAggregation(AggregationBuilders.count("price_count", "price"))
.addAggregation(AggregationBuilders.distinctCount(
"category_count", "category"))
.addAggregation(AggregationBuilders.percentiles(
"price_percentiles", "price")
.percentiles(Arrays.asList(50.0)))
.addGroupBy(GroupByBuilders.groupByField(
"category_group", "category").size(10))
.build();
SearchRequest request =
new SearchRequest("example_table", "example_index", searchQuery);
SearchResponse response = client.search(request);
AggregationResults aggregationResults = response.getAggregationResults();
System.out.println(aggregationResults
.getAsMinAggregationResult("min_price").getValue());
System.out.println(aggregationResults
.getAsMaxAggregationResult("max_price").getValue());
System.out.println(aggregationResults
.getAsSumAggregationResult("sum_price").getValue());
System.out.println(aggregationResults
.getAsAvgAggregationResult("avg_price").getValue());
System.out.println(aggregationResults
.getAsCountAggregationResult("price_count").getValue());
System.out.println(aggregationResults
.getAsDistinctCountAggregationResult("category_count").getValue());
System.out.println(aggregationResults
.getAsPercentilesAggregationResult("price_percentiles")
.getPercentilesAggregationItems());
GroupByFieldResult groupResult = response.getGroupByResults()
.getAsGroupByFieldResult("category_group");
for (GroupByFieldResultItem item :
groupResult.getGroupByFieldResultItems()) {
System.out.println(item.getKey() + ": " + item.getRowCount());
}
參數說明
查詢請求
request 的類型為 SearchRequest,包含以下參數。
|
名稱 |
類型 |
說明 |
|
tableName(必選) |
String |
資料表名稱。 |
|
indexName(必選) |
String |
多元索引名稱。 |
|
searchQuery(必選) |
SearchQuery |
查詢條件和統計彙總配置。 |
|
columnsToGet(可選) |
SearchRequest.ColumnsToGet |
返回列配置。僅 |
|
timeoutInMillisecond(可選) |
int |
請求級查詢逾時時間,單位為毫秒。預設值為 |
|
routingValues(可選) |
|
自訂路由欄位對應的主索引值列表。未配置自訂路由時無需設定。 |
查詢配置
request.searchQuery 的類型為 SearchQuery,包含以下與統計彙總相關的參數。
|
名稱 |
類型 |
說明 |
|
query(必選) |
Query |
統計範圍對應的查詢條件。對多元索引中的全部資料統計時,設定為 |
|
aggregationList(可選) |
|
指標彙總配置。與 |
|
groupByList(可選) |
|
分組配置。與 |
|
limit(可選) |
Integer |
本次查詢返回的最大行數,預設值為 |
|
offset(可選) |
Integer |
本次查詢的起始行位置,預設值為 |
|
sort(可選) |
Sort |
查詢結果的排序方式,不影響指標彙總和普通分組的計算範圍。 |
|
trackTotalCount(可選) |
int |
期望統計的最大匹配行數。設定為 |
|
filter(可選) |
SearchFilter |
對 |
指標彙總
以下參數對象添加到 request.searchQuery.aggregationList[]。aggName 用於從返回結果中擷取對應彙總結果,同一請求中的名稱必須唯一。
MinAggregation、MaxAggregation 和 AvgAggregation
|
名稱 |
類型 |
說明 |
|
aggName(必選) |
String |
彙總名稱。 |
|
fieldName(必選) |
String |
彙總欄位名稱,支援 Long、Double 和 Date 類型。 |
|
missing(可選) |
ColumnValue |
缺少 |
SumAggregation
|
名稱 |
類型 |
說明 |
|
aggName(必選) |
String |
彙總名稱。 |
|
fieldName(必選) |
String |
彙總欄位名稱,支援 Long 和 Double 類型。 |
|
missing(可選) |
ColumnValue |
缺少 |
CountAggregation
|
名稱 |
類型 |
說明 |
|
aggName(必選) |
String |
彙總名稱。 |
|
fieldName(必選) |
String |
要統計非空值行數的欄位名稱,支援 Long、Double、Boolean、Keyword、Date、IP 和 Geo_point 類型。稀疏列中缺少該欄位的行不計入結果。 |
如果要統計查詢匹配總行數,在 SearchQuery 中設定 trackTotalCount,並讀取 SearchResponse.totalCount。如果要統計多元索引中的全部行,將查詢類型設定為 MatchAllQuery。
DistinctCountAggregation
|
名稱 |
類型 |
說明 |
|
aggName(必選) |
String |
彙總名稱。 |
|
fieldName(必選) |
String |
要去重統計的欄位名稱,支援 Long、Double、Boolean、Keyword、Date、IP 和 Geo_point 類型。 |
|
missing(可選) |
ColumnValue |
缺少 |
PercentilesAggregation
|
名稱 |
類型 |
說明 |
|
aggName(必選) |
String |
彙總名稱。 |
|
fieldName(必選) |
String |
彙總欄位名稱,支援 Long、Double 和 Date 類型。 |
|
percentiles(必選) |
|
要計算的百分位元列表,例如 |
|
missing(可選) |
ColumnValue |
缺少 |
TopRowsAggregation
TopRowsAggregation 作為分組的子彙總使用。
|
名稱 |
類型 |
說明 |
|
aggName(必選) |
String |
彙總名稱。 |
|
limit(可選) |
Integer |
每個分組內最多返回的行數,預設值為 |
|
sort(可選) |
Sort |
分組內行的排序方式。 |
返回哪些屬性列由 request.columnsToGet 控制。要直接從多元索引返回屬性列,請在建立多元索引時儲存相應欄位;未指定返回列時只返回主鍵。
分組
以下參數對象添加到 request.searchQuery.groupByList[]。groupByName 用於從返回結果中擷取對應分組結果,同一請求中的名稱必須唯一。
GroupByField
|
名稱 |
類型 |
說明 |
|
groupByName(必選) |
String |
分組名稱。 |
|
fieldName(必選) |
String |
分組欄位名稱,支援 Long、Double、Boolean、Keyword、Date 和 IP 類型。 |
|
size(可選) |
Integer |
返回的分組數,預設值為 |
|
minDocCount(可選) |
Long |
分組內最少行數。行數小於該值的分組不返回。 |
|
groupBySorters(可選) |
|
分組定序。預設按行數降序排列。多個規則按添加順序生效。 |
|
subAggregations(可選) |
|
子指標彙總,對每個分組內的資料計算指標。 |
|
subGroupBys(可選) |
|
子分組,對每個父分組內的資料繼續分組。 |
groupBySorters[] 支援以下取值。
|
取值 |
說明 |
|
groupKeySortInAsc |
按分組值的字典序升序排列。 |
|
groupKeySortInDesc |
按分組值的字典序降序排列。 |
|
rowCountSortInAsc |
按分組行數升序排列。 |
|
rowCountSortInDesc |
按分組行數降序排列,預設規則。 |
|
subAggSortInAsc |
按指定子指標彙總的值升序排列。 |
|
subAggSortInDesc |
按指定子指標彙總的值降序排列。 |
GroupByComposite
|
名稱 |
類型 |
說明 |
|
groupByName(必選) |
String |
分組名稱。 |
|
sources(必選) |
|
多欄位分組源,最多包含 32 個欄位。支援 |
|
nextToken(可選) |
String |
下一頁分組憑證。首次請求不設定;返回結果中的 |
|
size(可選) |
Integer |
返回的分組數,預設值為 |
|
suggestedSize(可選) |
Integer |
面向 Spark、Presto 等計算引擎高吞吐情境的軟式節流。可設定為 |
|
subAggregations(可選) |
|
子指標彙總。 |
|
subGroupBys(可選) |
|
子分組。 |
nextToken 在 Java SDK 中以字串表示。持久化或跨系統傳輸時,不要改變字串內容。
GroupByRange
|
名稱 |
類型 |
說明 |
|
groupByName(必選) |
String |
分組名稱。 |
|
fieldName(必選) |
String |
分組欄位名稱,支援 Long 和 Double 類型。 |
|
ranges(必選) |
|
分組範圍列表。每個範圍為左閉右開區間 |
|
subAggregations(可選) |
|
子指標彙總。 |
|
subGroupBys(可選) |
|
子分組。 |
GroupByGeoDistance
|
名稱 |
類型 |
說明 |
|
groupByName(必選) |
String |
分組名稱。 |
|
fieldName(必選) |
String |
分組欄位名稱,僅支援 Geo_point 類型。 |
|
origin(必選) |
GeoPoint |
中心點座標,構造參數依次為緯度和經度。緯度範圍為 |
|
ranges(必選) |
|
距離範圍列表,單位為米。每個範圍為左閉右開區間 |
|
subAggregations(可選) |
|
子指標彙總。 |
|
subGroupBys(可選) |
|
子分組。 |
GroupByFilter
|
名稱 |
類型 |
說明 |
|
groupByName(必選) |
String |
分組名稱。 |
|
filters(必選) |
|
過濾條件列表。結果順序與過濾條件添加順序一致。 |
|
subAggregations(可選) |
|
子指標彙總。 |
|
subGroupBys(可選) |
|
子分組。 |
GroupByHistogram
|
名稱 |
類型 |
說明 |
|
groupByName(必選) |
String |
分組名稱。 |
|
fieldName(必選) |
String |
分組欄位名稱,支援 Long 和 Double 類型。 |
|
interval(必選) |
ColumnValue |
長條圖間隔。 |
|
fieldRange(可選) |
FieldRange |
統計範圍,包含 |
|
offset(可選) |
ColumnValue |
桶邊界相對預設起點的位移量。 |
|
minDocCount(可選) |
Long |
分組內最少行數。行數小於該值的桶不返回。 |
|
missing(可選) |
ColumnValue |
缺少 |
|
groupBySorters(可選) |
|
桶定序。 |
|
subAggregations(可選) |
|
子指標彙總。 |
|
subGroupBys(可選) |
|
子分組。 |
GroupByDateHistogram
Java SDK 5.16.1 及以上版本支援日期長條圖統計。Java SDK 5.13.9 及以上版本支援多元索引 Date 類型。版本資訊請參見Java SDK 歷史迭代版本。
|
名稱 |
類型 |
說明 |
|
groupByName(必選) |
String |
分組名稱。 |
|
fieldName(必選) |
String |
分組欄位名稱,僅支援 Date 類型。 |
|
interval(必選) |
DateTimeValue |
日期或時間間隔,由數值和 |
|
fieldRange(可選) |
FieldRange |
統計範圍,包含 |
|
minDocCount(可選) |
Long |
分組內最少行數。行數小於該值的桶不返回。 |
|
missing(可選) |
ColumnValue |
缺少 |
|
timeZone(可選) |
String |
時區,格式為 |
|
groupBySorters(可選) |
|
桶定序。 |
|
subAggregations(可選) |
|
子指標彙總。 |
|
subGroupBys(可選) |
|
子分組。 |
GroupByGeoGrid
|
名稱 |
類型 |
說明 |
|
groupByName(必選) |
String |
分組名稱。 |
|
fieldName(必選) |
String |
分組欄位名稱,僅支援 Geo_point 類型。 |
|
precision(必選) |
GeoHashPrecision |
GeoHash 網格精度,從約 5009 km × 4992 km 的 |
|
size(可選) |
Integer |
返回的網格分組數。 |
|
subAggregations(可選) |
|
子指標彙總。 |
|
subGroupBys(可選) |
|
子分組。 |
傳回值
search 方法返回 SearchResponse,與統計彙總相關的核心欄位如下。
|
名稱 |
類型 |
說明 |
|
aggregationResults |
AggregationResults |
指標彙總結果,通過 |
|
groupByResults |
GroupByResults |
分組結果,通過 |
|
totalCount |
long |
查詢匹配行數,通過 |
|
isAllSuccess |
boolean |
是否已成功查詢全部索引分割區,通過 |
指標彙總結果
|
配置類型 |
結果類型 |
結果欄位和擷取方法 |
|
MinAggregation |
MinAggregationResult |
|
|
MaxAggregation |
MaxAggregationResult |
|
|
SumAggregation |
SumAggregationResult |
|
|
AvgAggregation |
AvgAggregationResult |
|
|
CountAggregation |
CountAggregationResult |
|
|
DistinctCountAggregation |
DistinctCountAggregationResult |
|
|
PercentilesAggregation |
PercentilesAggregationResult |
|
|
TopRowsAggregation |
TopRowsAggregationResult |
|
分組結果
|
配置類型 |
結果類型 |
核心結果欄位 |
|
GroupByField |
GroupByFieldResult |
|
|
GroupByComposite |
GroupByCompositeResult |
|
|
GroupByRange |
GroupByRangeResult |
|
|
GroupByGeoDistance |
GroupByGeoDistanceResult |
|
|
GroupByFilter |
GroupByFilterResult |
|
|
GroupByHistogram |
GroupByHistogramResult |
|
|
GroupByDateHistogram |
GroupByDateHistogramResult |
|
|
GroupByGeoGrid |
GroupByGeoGridResult |
|
情境樣本
使用子彙總和子分組
以下樣本按類別分組,在每個類別中計算最高價格,並繼續按城市分組。分組定序按添加順序生效。
SearchQuery searchQuery = SearchQuery.newBuilder()
.query(QueryBuilders.matchAll())
.limit(0)
.addGroupBy(GroupByBuilders.groupByField(
"category_group", "category")
.size(10)
.addGroupBySorter(GroupBySorter.groupKeySortInAsc())
.addSubAggregation(AggregationBuilders.max(
"max_price", "price"))
.addSubGroupBy(GroupByBuilders.groupByField(
"city_group", "city").size(10)))
.build();
SearchRequest request =
new SearchRequest("example_table", "example_index", searchQuery);
SearchResponse response = client.search(request);
GroupByFieldResult result = response.getGroupByResults()
.getAsGroupByFieldResult("category_group");
for (GroupByFieldResultItem item :
result.getGroupByFieldResultItems()) {
double maxPrice = item.getSubAggregationResults()
.getAsMaxAggregationResult("max_price")
.getValue();
GroupByFieldResult cityResult = item.getSubGroupByResults()
.getAsGroupByFieldResult("city_group");
System.out.println(item.getKey() + ": " + maxPrice);
System.out.println(cityResult.getGroupByFieldResultItems());
}
使用多欄位分組並翻頁
GroupByComposite 將多列鍵以扁平結構返回,並支援通過 nextToken 翻頁。
GroupByComposite.Builder compositeBuilder = GroupByBuilders
.groupByComposite("category_city_group")
.addSources(GroupByBuilders.groupByField(
"category", "category")
.addGroupBySorter(GroupBySorter.groupKeySortInAsc()))
.addSources(GroupByBuilders.groupByField(
"city", "city")
.addGroupBySorter(GroupBySorter.groupKeySortInAsc()))
.size(100);
String nextToken = null;
do {
GroupByComposite groupBy = nextToken == null
? compositeBuilder.build()
: compositeBuilder.nextToken(nextToken).build();
SearchQuery searchQuery = SearchQuery.newBuilder()
.query(QueryBuilders.matchAll())
.limit(0)
.addGroupBy(groupBy)
.build();
SearchRequest request = new SearchRequest(
"example_table", "example_index", searchQuery);
SearchResponse response = client.search(request);
GroupByCompositeResult result = response.getGroupByResults()
.getAsGroupByCompositeResult("category_city_group");
for (GroupByCompositeResultItem item :
result.getGroupByCompositeResultItems()) {
System.out.println(item.getKeys() + ": " + item.getRowCount());
}
nextToken = result.getNextToken();
} while (nextToken != null);
按範圍、距離和過濾條件分組
以下代碼展示三種分組的核心配置。它們可以在同一個 SearchQuery 中組合。
GroupByRange priceRanges = GroupByBuilders
.groupByRange("price_ranges", "price")
.addRange(0, 100)
.addRange(100, 500)
.build();
GroupByGeoDistance distanceRanges = GroupByBuilders
.groupByGeoDistance("distance_ranges", "location")
.origin(30.2741, 120.1551)
.addRange(0, 10000)
.addRange(10000, 100000)
.build();
GroupByFilter categoryFilters = GroupByBuilders
.groupByFilter("category_filters")
.addFilter(QueryBuilders.term("category", "books"))
.addFilter(QueryBuilders.term("category", "games"))
.build();
產生數值和日期長條圖
以下樣本分別按 20 的數值間隔和 1 個月的日期間隔分組。
GroupByHistogram priceHistogram = GroupByBuilders
.groupByHistogram("price_histogram", "price")
.interval(20)
.offset(0)
.minDocCount(1L)
.addFieldRange(0, 100)
.addGroupBySorter(GroupBySorter.groupKeySortInAsc())
.build();
GroupByDateHistogram dateHistogram = GroupByBuilders
.groupByDateHistogram("date_histogram", "event_date")
.interval(1, DateTimeUnit.MONTH)
.fieldRange("2026-01-01", "2026-06-01")
.timeZone("+08:00")
.minDocCount(1L)
.addGroupBySorter(GroupBySorter.groupKeySortInAsc())
.build();
SearchQuery searchQuery = SearchQuery.newBuilder()
.query(QueryBuilders.matchAll())
.limit(0)
.addGroupBy(priceHistogram)
.addGroupBy(dateHistogram)
.build();
SearchResponse response = client.search(new SearchRequest(
"example_table", "example_index", searchQuery));
按地理網格分組
以下樣本按約 39 km × 19 km 的 GeoHash 網格統計地理位置欄位。
SearchQuery searchQuery = SearchQuery.newBuilder()
.query(QueryBuilders.matchAll())
.limit(0)
.addGroupBy(GroupByBuilders.groupByGeoGrid(
"geo_grid", "location")
.precision(GeoHashPrecision.GHP_39KM_19KM_4)
.size(100))
.build();
SearchResponse response = client.search(new SearchRequest(
"example_table", "example_index", searchQuery));
GroupByGeoGridResult result = response.getGroupByResults()
.getAsGroupByGeoGridResult("geo_grid");
System.out.println(result.getGroupByGeoGridResultItems());
擷取分組內的行
以下樣本按類別分組,並返回每個類別中價格最高的一行。
SearchQuery searchQuery = SearchQuery.newBuilder()
.query(QueryBuilders.matchAll())
.limit(0)
.addGroupBy(GroupByBuilders.groupByField(
"category_group", "category")
.size(10)
.addSubAggregation(AggregationBuilders.topRows(
"top_price")
.limit(1)
.sort(new Sort(Arrays.asList(
new FieldSort(
"price", SortOrder.DESC))))))
.build();
SearchRequest.ColumnsToGet columnsToGet =
new SearchRequest.ColumnsToGet();
columnsToGet.setColumns(Arrays.asList("category", "price"));
SearchRequest request =
new SearchRequest("example_table", "example_index", searchQuery);
request.setColumnsToGet(columnsToGet);
SearchResponse response = client.search(request);
GroupByFieldResult result = response.getGroupByResults()
.getAsGroupByFieldResult("category_group");
for (GroupByFieldResultItem item :
result.getGroupByFieldResultItems()) {
List<Row> rows = item.getSubAggregationResults()
.getAsTopRowsAggregationResult("top_price")
.getRows();
System.out.println(item.getKey() + ": " + rows);
}
多欄位分組方式對比
按多個欄位分組時,可嵌套多個 GroupByField,也可直接使用 GroupByComposite。根據是否需要分組翻頁、返回結構和定序選擇。
|
對比項 |
欄位分組嵌套 |
多欄位分組 |
|
配置方式 |
在父 |
在 |
|
分組數量 |
每層最多返回 2000 個分組。 |
每頁最多返回 2000 個分組。 |
|
欄位數量 |
最多嵌套 3 層。 |
最多 32 個欄位。 |
|
返回結構 |
按父子層級嵌套返回。 |
多列鍵以扁平列表返回。 |
|
翻頁 |
不支援。 |
支援通過 |
|
排序 |
支援按分組值、行數或子彙總值排序。 |
每個分組源僅支援按分組值字典序排序,預設降序。 |
|
子彙總 |
支援。 |
支援。 |
|
Date 欄位相容性 |
按欄位定義的日期格式返回分組鍵。 |
日期分組鍵以時間戳記字串返回。 |