通過多元索引的統計彙總功能,可對查詢結果執行值計算和分組統計。值計算包括最小值、最大值、求和、平均值、統計行數、去重統計行數和百分位統計。分組統計支援按欄位值、範圍、地理位置、過濾條件、長條圖和多欄位組合等方式分組。多個統計彙總可組合使用。
Python SDK 5.2.1 及以上版本開始支援統計彙總功能。
功能列表
統計彙總的詳細功能請參見下表。
值彙總
功能 | 說明 |
最小值 | 返回一個欄位中的最小值,類似於 SQL 中的 min。 |
最大值 | 返回一個欄位中的最大值,類似於 SQL 中的 max。 |
和 | 返回數值欄位的總數,類似於 SQL 中的 sum。 |
平均值 | 返回數值欄位的平均值,類似於 SQL 中的 avg。 |
統計行數 | 返回指定欄位值的數量或者多元索引資料總行數,類似於 SQL 中的 count。 |
去重統計行數 | 返回指定欄位不同值的數量,類似於 SQL 中的 count(distinct)。 |
百分位統計 | 百分位統計常用來統計一組資料的百分位分布情況,例如在日常系統營運中統計每次請求訪問的耗時情況時,需要關注系統請求耗時的 P25、P50、P90、P99 值等分布情況。 |
分組彙總
功能 | 說明 |
欄位值分組 | 根據一個欄位的值對查詢結果進行分組,相同的欄位值放到同一分組內,返回每個分組的值和該值對應的個數。 說明 當分組較大時,按欄位值分組可能會存在誤差。 |
範圍分組 | 根據一個欄位的範圍對查詢結果進行分組,欄位值在某範圍內放到同一分組內,返回每個範圍中相應的 item 個數。 |
地理位置分組 | 根據距離某一個中心點的範圍對查詢結果進行分組,距離差值在某範圍內放到同一分組內,返回每個範圍中相應的 item 個數。 |
過濾條件分組 | 按照過濾條件對查詢結果進行分組,擷取每個過濾條件匹配到的數量,返回結果的順序和添加過濾條件的順序一致。 |
長條圖統計 | 按照指定資料間隔對查詢結果進行分組,欄位值在相同範圍內放到同一分組內,返回每個分組的值和該值對應的個數。 |
多欄位分組 | 根據多個欄位對查詢結果進行組合分組,類似於 SQL 中的 |
值彙總
最小值
返回一個欄位中的最小值,類似於 SQL 中的 min。
參數
參數 | 說明 |
name | 自訂的統計彙總名稱,用於區分不同彙總並擷取對應結果。 |
field | 用於統計彙總的欄位,僅支援 Long、Double 和 Date 類型。 |
missing | 欄位為空白時的預設值。未設定時忽略該行;設定後以該值參與統計彙總。 |
樣本
統計年齡為 18 歲的人中得分的最低分數。
query = TermQuery('age', 18)
agg = Min('score', name='min')
search_response = client.search(table_name, index_name,
SearchQuery(query, limit=0, aggs=[agg]),
ColumnsToGet(return_type=ColumnReturnType.ALL_FROM_INDEX))
for agg_result in search_response.agg_results:
print("name: %s, value: %s" % (agg_result.name, str(agg_result.value)))最大值
返回一個欄位中的最大值,類似於 SQL 中的 max。
參數
參數 | 說明 |
name | 自訂的統計彙總名稱,用於區分不同彙總並擷取對應結果。 |
field | 用於統計彙總的欄位,僅支援 Long、Double 和 Date 類型。 |
missing | 欄位為空白時的預設值。未設定時忽略該行;設定後以該值參與統計彙總。 |
樣本
統計年齡為 18 歲的人中得分的最高分數。如果某人沒有分數,則對應分數的預設值為 0。
query = TermQuery('age', 18)
agg = Max('score', missing_value=0, name='max')
search_response = client.search(table_name, index_name,
SearchQuery(query, limit=0, aggs=[agg]),
ColumnsToGet(return_type=ColumnReturnType.ALL_FROM_INDEX))
for agg_result in search_response.agg_results:
print("name: %s, value: %s" % (agg_result.name, str(agg_result.value)))和
返回數值欄位的總數,類似於 SQL 中的 sum。
參數
參數 | 說明 |
name | 自訂的統計彙總名稱,用於區分不同彙總並擷取對應結果。 |
field | 用於統計彙總的欄位,僅支援 Long 和 Double 類型。 |
missing | 欄位為空白時的預設值。未設定時忽略該行;設定後以該值參與統計彙總。 |
樣本
統計年齡為 18 歲的所有人得分的總和。
query = TermQuery('age', 18)
agg = Sum('score', name='sum')
search_response = client.search(table_name, index_name,
SearchQuery(query, limit=0, aggs=[agg]),
ColumnsToGet(return_type=ColumnReturnType.ALL_FROM_INDEX))
for agg_result in search_response.agg_results:
print("name: %s, value: %s" % (agg_result.name, str(agg_result.value)))平均值
返回數值欄位的平均值,類似於 SQL 中的 avg。
參數
參數 | 說明 |
name | 自訂的統計彙總名稱,用於區分不同彙總並擷取對應結果。 |
field | 用於統計彙總的欄位,僅支援 Long、Double 和 Date 類型。 |
missing | 欄位為空白時的預設值。未設定時忽略該行;設定後以該值參與統計彙總。 |
樣本
統計年齡為 18 歲的所有人得分的平均分。
query = TermQuery('age', 18)
agg = Avg('score', name='avg')
search_response = client.search(table_name, index_name,
SearchQuery(query, limit=0, aggs=[agg]),
ColumnsToGet(return_type=ColumnReturnType.ALL_FROM_INDEX))
for agg_result in search_response.agg_results:
print("name: %s, value: %s" % (agg_result.name, str(agg_result.value)))統計行數
返回指定欄位值的數量或者多元索引資料總行數,類似於 SQL 中的 count。
通過如下方式可以統計多元索引資料總行數或者某個 query 匹配的行數。
使用統計彙總的 count 功能,在請求中設定 count(*)。
使用 query 功能的匹配行數,在 query 中設定 setGetTotalCount(true);如果需要統計多元索引資料總行數,則使用 MatchAllQuery。
如果需要擷取多元索引資料某列出現的次數,則使用 count(列名),可應用於稀疏列的情境。
參數
參數 | 說明 |
name | 自訂的統計彙總名稱,用於區分不同彙總並擷取對應結果。 |
field | 用於統計彙總的欄位,僅支援 Long、Double、Boolean、Keyword、Geo_point 和 Date 類型。 |
樣本
統計年齡為 18 歲的人中參加考試有分數的人數。
query = TermQuery('age', 18)
agg = Count('score', name='count')
search_response = client.search(table_name, index_name,
SearchQuery(query, limit=0, aggs=[agg]),
ColumnsToGet(return_type=ColumnReturnType.ALL_FROM_INDEX))
for agg_result in search_response.agg_results:
print("name: %s, value: %s" % (agg_result.name, str(agg_result.value)))去重統計行數
返回指定欄位不同值的數量,類似於 SQL 中的 count(distinct)。
去重統計行數的計算結果是個近似值。
當去重統計行數小於 1 萬時,計算結果接近精確值。
當去重統計行數達到 1 億時,計算結果的誤差為 2% 左右。
參數
參數 | 說明 |
name | 自訂的統計彙總名稱,用於區分不同彙總並擷取對應結果。 |
field | 用於統計彙總的欄位,僅支援 Long、Double、Boolean、Keyword、Geo_point 和 Date 類型。 |
missing | 欄位為空白時的預設值。未設定時忽略該行;設定後以該值參與統計彙總。 |
樣本
去重統計年齡為 18 歲的人中一共有多少種不同的姓名。
query = TermQuery('age', 18)
agg = DistinctCount('name', name='distinct_name')
search_response = client.search(table_name, index_name,
SearchQuery(query, limit=0, aggs=[agg]),
ColumnsToGet(return_type=ColumnReturnType.ALL_FROM_INDEX))
for agg_result in search_response.agg_results:
print("name: %s, value: %s" % (agg_result.name, str(agg_result.value)))百分位統計
百分位統計常用來統計一組資料的百分位分布情況,例如在日常系統營運中統計每次請求訪問的耗時情況時,需要關注系統請求耗時的 P25、P50、P90、P99 值等分布情況。
百分位統計為非精確統計,對不同百分位元值的計算精確度不同,較為極端的百分位元值更加準確,例如 1% 或 99% 的百分位元值會比 50% 的百分位元值準確。
參數
參數 | 說明 |
name | 自訂的統計彙總名稱,用於區分不同彙總並擷取對應結果。 |
field | 用於統計彙總的欄位,僅支援 Long、Double 和 Date 類型。 |
percentiles | 百分位值列表,如 50、90、99,支援設定一個或多個。 |
missing_value | 欄位為空白時的預設值。未設定時忽略該行;設定後以該值參與統計彙總。 |
樣本
query = TermQuery('product', '10010')
agg = Percentiles('latency', percentiles_list=[50, 90, 95])
search_response = client.search(table_name, index_name,
SearchQuery(query, limit=0, aggs=[agg]),
ColumnsToGet(return_type=ColumnReturnType.ALL_FROM_INDEX))
for agg_result in search_response.agg_results:
print("name: %s" % agg_result.name)
for item in agg_result.value:
print(" percentile: %s, value: %s" % (str(item.key), str(item.value)))分組彙總
欄位值分組
根據一個欄位的值對查詢結果進行分組,相同的欄位值放到同一分組內,返回每個分組的值和該值對應的個數。
當分組較大時,按欄位值分組可能會存在誤差。
參數
參數 | 說明 |
name | 自訂的統計彙總名稱,用於區分不同彙總並擷取對應結果。 |
field | 用於統計彙總的欄位,僅支援 Long、Double、Boolean、Keyword 和 Date 類型。 |
size | 返回的分組數量,預設值為 10。最大值為 2000。當分組數量超過 2000 時,只會返回前 2000 個分組。 |
group_by_sort | 分組中的 item 定序,預設按 item 數量降序排序,設定多個時按添加順序依次排列。支援按值的字典序、行數、子統計彙總結果值升序或降序排列。 |
sub_aggs 和 sub_group_bys | 子統計彙總,根據分組內容做進一步彙總分析。例如按類別分組後添加 Max 和 Min 子彙總,即可得到每個類別的商品數量及價格的最大值和最小值。 |
樣本 1
將年齡為 18 歲的人按分數分組,並擷取人數最多的 10 個分數值以及每個分數的人數。
query = TermQuery('age', 18)
group_by = GroupByField('score', size=10)
search_response = client.search(table_name, index_name,
SearchQuery(query, limit=0, group_bys=[group_by]),
ColumnsToGet(return_type=ColumnReturnType.ALL_FROM_INDEX))
for group_by_result in search_response.group_by_results:
print("name: %s" % group_by_result.name)
for item in group_by_result.items:
print(" key: %s, count: %d" % (item.key, item.row_count))樣本 2
將年齡為 18 歲的人按分數分組,並擷取人數最少的 2 個分數值以及每個分數的人數。
group_by = GroupByField('score', size=2, group_by_sort=[RowCountSort(sort_order=SortOrder.ASC)])
search_response = client.search(table_name, index_name,
SearchQuery(TermQuery('age', 18), limit=0, get_total_count=True, group_bys=[group_by]),
ColumnsToGet(return_type=ColumnReturnType.ALL_FROM_INDEX))
for group_by_result in search_response.group_by_results:
print("name: %s" % group_by_result.name)
for item in group_by_result.items:
print(" key: %s, count: %d" % (item.key, item.row_count))樣本 3
將年齡為 18 歲的人按分數分組,並擷取人數最多的 2 個分數值、每個分數的人數以及按主鍵排序前三的人的資訊。
sort = RowCountSort(sort_order=SortOrder.DESC)
sub_agg = [TopRows(limit=3, sort=Sort([PrimaryKeySort(sort_order=SortOrder.DESC)]), name='top_rows')]
group_by = GroupByField('score', size=2, group_by_sort=[sort], sub_aggs=sub_agg)
search_response = client.search(table_name, index_name,
SearchQuery(TermQuery('age', 18), limit=0, get_total_count=True, group_bys=[group_by]),
ColumnsToGet(return_type=ColumnReturnType.ALL_FROM_INDEX))
for group_by_result in search_response.group_by_results:
print("name: %s" % group_by_result.name)
for item in group_by_result.items:
print(" key: %s, count: %d" % (item.key, item.row_count))
for sub_agg in item.sub_aggs:
print(" sub_agg: %s" % sub_agg.name)
for entry in sub_agg.value:
print(" value: %s" % str(entry))樣本 4
將年齡為 18 歲的人按分數和性別分組。
sort = RowCountSort(sort_order=SortOrder.ASC)
sub_group = GroupByField('sex', size=10, group_by_sort=[sort])
group_by = GroupByField('score', size=10, group_by_sort=[sort], sub_group_bys=[sub_group])
search_response = client.search(table_name, index_name,
SearchQuery(TermQuery('age', 18), limit=0, get_total_count=True, group_bys=[group_by]),
ColumnsToGet(return_type=ColumnReturnType.ALL_FROM_INDEX))
for group_by_result in search_response.group_by_results:
print("name: %s" % group_by_result.name)
for item in group_by_result.items:
print(" key: %s, count: %d" % (item.key, item.row_count))
for sub_group in item.sub_group_bys:
print(" sub_group: %s" % sub_group.name)
for sub_item in sub_group.items:
print(" key: %s, count: %s" % (str(sub_item.key), str(sub_item.row_count)))範圍分組
根據一個欄位的範圍對查詢結果進行分組,欄位值在某範圍內放到同一分組內,返回每個範圍中相應的 item 個數。
參數
參數 | 說明 |
name | 自訂的統計彙總名稱,用於區分不同彙總並擷取對應結果。 |
field | 用於統計彙總的欄位,僅支援 Long 和 Double 類型。 |
range[double_from, double_to) | 分組的範圍。起始值 double_from 可以使用最小值 Double.MIN_VALUE,結束值 double_to 可以使用最大值 Double.MAX_VALUE。 |
sub_aggs 和 sub_group_bys | 子統計彙總,根據分組內容做進一步彙總分析。例如按銷量分組後再按省份分組,即可獲得某個銷量範圍內哪個省比重比較大,實現方法是 GroupByRange 下添加一個 GroupByField。 |
樣本
統計年齡為 18 歲的人中得分的分數在 [80, 90) 和 [90, 100) 兩個區間段的人數。
query = TermQuery('age', 18)
group_by = GroupByRange(field_name='score', ranges=[(80, 90), (90, 100)])
search_response = client.search(table_name, index_name,
SearchQuery(query, limit=0, group_bys=[group_by]),
ColumnsToGet(return_type=ColumnReturnType.ALL_FROM_INDEX))
for group_by_result in search_response.group_by_results:
print("name: %s" % group_by_result.name)
for item in group_by_result.items:
print(" range: %.1f~%.1f, count: %d" % (item.range_from, item.range_to, item.row_count))地理位置分組
根據距離某一個中心點的範圍對查詢結果進行分組,距離差值在某範圍內放到同一分組內,返回每個範圍中相應的 item 個數。
參數
參數 | 說明 |
name | 自訂的統計彙總名稱,用於區分不同彙總並擷取對應結果。 |
field | 用於統計彙總的欄位,僅支援 Geo_point 類型。 |
origin(double lat, double lon) | 起始中心點的經緯度。lat 是起始中心點座標緯度,lon 是起始中心點座標經度。 |
range[double_from, double_to) | 分組的範圍,單位為米。起始值 double_from 可以使用最小值 Double.MIN_VALUE,結束值 double_to 可以使用最大值 Double.MAX_VALUE。 |
sub_aggs 和 sub_group_bys | 子統計彙總,根據分組內容做進一步彙總分析。 |
樣本
統計年齡為 18 歲的人中家庭住址在距離學校一公裡以內和一公裡到兩公裡內的人數。其中學校經緯度為(31,116)。
query = TermQuery('age', 18)
group_by = GroupByGeoDistance(field_name='address', origin=GeoPoint(31, 116), ranges=[(0, 1000), (1000, 2000)])
search_response = client.search(table_name, index_name,
SearchQuery(query, limit=0, group_bys=[group_by]),
ColumnsToGet(return_type=ColumnReturnType.ALL_FROM_INDEX))
for group_by_result in search_response.group_by_results:
print("name: %s" % group_by_result.name)
for item in group_by_result.items:
print(" range: %.1f~%.1f, count: %d" % (item.range_from, item.range_to, item.row_count))過濾條件分組
按照過濾條件對查詢結果進行分組,擷取每個過濾條件匹配到的數量,返回結果的順序和添加過濾條件的順序一致。
參數
參數 | 說明 |
name | 自訂的統計彙總名稱,用於區分不同彙總並擷取對應結果。 |
filter | 過濾條件,返回結果的順序和添加過濾條件的順序一致。 |
sub_aggs 和 sub_group_bys | 子統計彙總,根據分組內容做進一步彙總分析。 |
樣本
分別統計年齡為 18 歲的人中數學考了 100 分和語文考了 100 分的人數。
query = TermQuery('age', 18)
filter1 = TermQuery('math', 100)
filter2 = TermQuery('chinese', 100)
filters = [filter1, filter2]
group_by = GroupByFilter(filters)
search_response = client.search(table_name, index_name,
SearchQuery(query, limit=0, group_bys=[group_by]),
ColumnsToGet(return_type=ColumnReturnType.ALL_FROM_INDEX))
for group_by_result in search_response.group_by_results:
print("name: %s" % group_by_result.name)
i = 0
for item in group_by_result.items:
print(" filter: %s=%s, count: %d" % (str(filters[i].field_name), str(filters[i].column_value), item.row_count))
i += 1長條圖統計
按照指定資料間隔對查詢結果進行分組,欄位值在相同範圍內放到同一分組內,返回每個分組的值和該值對應的個數。
參數
參數 | 說明 |
name | 自訂的統計彙總名稱,用於區分不同彙總並擷取對應結果。 |
field | 用於統計彙總的欄位,僅支援 Long 和 Double 類型。 |
interval | 統計間隔。 |
field_range[min,max] | 統計範圍,與 interval 參數配合使用限制分組的數量。(fieldRange.max-fieldRange.min)/interval 的值不能超過 2000。 |
min_doc_count | 最小行數。當分組中的行數小於最小行數時,不會返回此分組的統計結果。 |
missing_value | 欄位為空白時的預設值。未設定時忽略該行;設定後以該值參與統計彙總。 |
樣本
query = TermQuery('product', '10010')
group_by = GroupByHistogram(field_name='latency', interval=100, field_range=FieldRange(0, 10000), missing_value=0)
search_response = client.search(table_name, index_name,
SearchQuery(query, limit=0, group_bys=[group_by]),
ColumnsToGet(return_type=ColumnReturnType.ALL_FROM_INDEX))
for group_by_result in search_response.group_by_results:
print("name: %s" % group_by_result.name)
for item in group_by_result.items:
print(" key: %s, value: %s" % (item.key, item.value))多欄位分組
根據多個欄位對查詢結果進行組合分組,類似於 SQL 中的 GROUP BY column1, column2, ...。與欄位值分組不同,多欄位分組支援多個資料來源同時分組,並支援翻頁擷取所有分組結果。sources 中最多允許 32 個資料來源。
Python SDK 6.4.4 及以上版本開始支援多欄位分組功能。
參數
參數 | 說明 |
name | 自訂的統計彙總名稱,用於區分不同彙總並擷取對應結果。預設值為 |
sources | 資料來源列表,支援多個 GroupBy 類型(如 說明
|
size | 每次返回的分組數量。選擇性參數,預設值為 10,最大值為 2000。精確控制返回的分組條數,超過最大值時服務端會返回錯誤。不能與 |
next_token | 翻頁標記。首次請求時無需設定,後續翻頁請求時使用上一次返回結果中的 |
suggested_size | 建議的分組數量。選擇性參數,支援任意正整數或 -1。建議模式,超過最大值(2000)時自動調整為最大值而不會報錯,設定為 -1 表示直接使用最大值。適用於資料探索、批量處理等希望儘可能多返回資料但不希望超限報錯的情境。不能與 |
sub_aggs 和 sub_group_bys | 子統計彙總,根據分組內容做進一步彙總分析。 |
返回結果中每個分組的
keys是字串列表,與 sources 中各資料來源的順序一一對應。當某個資料來源對應的欄位值為空白時,keys中對應位置的值為None。當分組數量較多時,建議設定
size或suggested_size參數並配合next_token進行翻頁擷取,避免單次返回資料量過大。當返回結果中next_token為None時,表示所有分組結果已擷取完畢。
樣本 1
按欄位 score 對年齡為 18 歲的人進行分組,擷取每個分數值對應的行數。
query = TermQuery('age', 18)
# 作為資料來源的 GroupByField 只需指定 field_name 和 name,不能設定 size
source = GroupByField('score', name='group_by_score')
group_by = GroupByComposite(sources=[source])
search_response = client.search(table_name, index_name,
SearchQuery(query, limit=0, get_total_count=True, group_bys=[group_by]),
ColumnsToGet(return_type=ColumnReturnType.NONE))
for group_by_result in search_response.group_by_results:
print("name: %s" % group_by_result.name)
print("source_names: %s" % str(group_by_result.source_group_by_names))
for item in group_by_result.items:
print(" keys: %s, count: %d" % (str(item.keys), item.row_count))樣本 2
按欄位 score 和 sex 對年齡為 18 歲的人進行組合分組,擷取每個分數和性別組合對應的行數。
query = TermQuery('age', 18)
source1 = GroupByField('score', name='group_by_score')
source2 = GroupByField('sex', name='group_by_sex')
group_by = GroupByComposite(sources=[source1, source2])
search_response = client.search(table_name, index_name,
SearchQuery(query, limit=0, get_total_count=True, group_bys=[group_by]),
ColumnsToGet(return_type=ColumnReturnType.NONE))
for group_by_result in search_response.group_by_results:
print("name: %s" % group_by_result.name)
print("source_names: %s" % str(group_by_result.source_group_by_names))
for item in group_by_result.items:
# keys 是字串列表,與 sources 順序一一對應;欄位值為空白時對應位置為 None
print(" keys: %s, count: %d" % (str(item.keys), item.row_count))樣本 3
使用 next_token 實現分頁擷取所有分組結果。按欄位 score 分組,每次擷取 2 個分組,通過翻頁擷取所有結果。
query = TermQuery('age', 18)
source = GroupByField('score')
group_by = GroupByComposite(sources=[source], size=2)
# 首次請求
search_response = client.search(table_name, index_name,
SearchQuery(query, limit=0, get_total_count=True, group_bys=[group_by]),
ColumnsToGet(return_type=ColumnReturnType.NONE))
group_by_result = search_response.group_by_results[0]
all_items = list(group_by_result.items)
# 翻頁擷取剩餘結果,next_token 為 None 時表示已擷取完畢
while group_by_result.next_token is not None:
group_by = GroupByComposite(sources=[source], size=2, next_token=group_by_result.next_token)
search_response = client.search(table_name, index_name,
SearchQuery(query, limit=0, get_total_count=True, group_bys=[group_by]),
ColumnsToGet(return_type=ColumnReturnType.NONE))
group_by_result = search_response.group_by_results[0]
all_items.extend(group_by_result.items)
# 輸出所有分組結果
for item in all_items:
print("keys: %s, count: %d" % (str(item.keys), item.row_count))樣本 4
使用子統計彙總。按欄位 score 分組後,統計每個分組中 score 的最大值。
query = TermQuery('age', 18)
source = GroupByField('score')
sub_agg = Max('score')
group_by = GroupByComposite(sources=[source], sub_aggs=[sub_agg])
search_response = client.search(table_name, index_name,
SearchQuery(query, limit=0, get_total_count=True, group_bys=[group_by]),
ColumnsToGet(return_type=ColumnReturnType.NONE))
for group_by_result in search_response.group_by_results:
print("name: %s" % group_by_result.name)
for item in group_by_result.items:
print(" keys: %s, count: %d" % (str(item.keys), item.row_count))
for sub_agg in item.sub_aggs:
print(" sub_agg: %s, value: %s" % (sub_agg.name, str(sub_agg.value)))