clickhouse 隨心所欲的聚合模型-AggregatingMergeTree

clickhouse 強大的 MergeTree 系列引擎令人信服,其 ReplacingMergeTree、SummingMergeTree 在數據唯一性和匯總場景中表現非凡。但你是否還有保留最小(大)、平均等預聚合需求,甚至在一個模型中既有唯一性語意也有匯總、最小、最大、平均值語意該如何處理。在 doris 中 Aggregate 數據模型可以輕松解決,那么同為頭部 AP 數據庫的 clickhouse 是否可以隨心所欲的定義聚合模型呢?

一、AggregatingMergeTree

1.1 基本使用

AggregatingMergeTree 表引擎作為 MergeTree 系列引擎也是遵循其家族的基本邏輯的,它能夠在合并分區的時候按照預先定義的方式聚合數據。與 ReplacingMergeTree、SummingMergeTree 不同的是表引擎已經內置好了聚合方式,用戶只能指定字段在分區合并時對字段進行去重或累加,AggregatingMergeTree 則進一步開發底層給用戶,用戶需要指定在分區合并時采用何種聚合函數,以及針對哪些字段進行計算,下面是該引擎的使用方式(復刻 doris 官方文檔的案例)

drop table if exists tbl_agg;
create table if not exists tbl_agg
(`user_id` String comment '用戶id',`date`    datetime comment '數據灌入日期時間',`city`    String comment '用戶所在城市',`age`     Int8 comment '用戶年齡',`sex`     Int8 comment '用戶性別',`last_visit_date` AggregateFunction(anyLast,DateTime) comment '用戶最后一次訪問時間',`cost` AggregateFunction(sum, Int256) comment '用戶總消費',`max_dwell_time` AggregateFunction(max,Int64) comment '用戶最大停留時間',`min_dwell_time` AggregateFunction(min,Int64) comment '用戶最小停留時間'
) engine AggregatingMergeTree()order by (user_id, date, city, age, sex);

AggregateFunction 是 clickhouse 提供的特殊數據類型,它能夠以二進制的形式存儲中間狀態結果。其使用方式也十分特殊,在定義的時候需要提供聚合方式以及數據類型。常用的聚合方式整理如下:

  1. count: 計數非空行數
  2. sum: 累加
  3. max: 最大值
  4. min: 最小值
  5. anyLast: 最后一個非空值
  6. uniq: 去重計數

當然 clickhouse 提供的聚合函數很多,詳情可以訪問: https://clickhouse.com/docs/en/sql-reference/aggregate-functions/reference

因為 AggregateFunction 是二進制存儲的中間結果,我們在插入數據時也需要將明文數據轉換為 AggregateFunction 可以接受的數據類型,clickhouse 為每個聚合函數都提供了轉換為 AggregateFunction 類型的 *State 函數

insert into tbl_agg
select 10000,'2017-10-01','北京',20,0,anyLastState(toDateTime('2017-10-01 06:00:00')),sumState(toInt256(20)),maxState(toInt64(10)),minState(toInt64(10));insert into tbl_agg
select 10000,'2017-10-01','北京',20,0,anyLastState(toDateTime('2017-10-01 07:00:00')),sumState(toInt256(15)),maxState(toInt64(2)),minState(toInt64(2));

同理我們在查詢是也需要特殊的函數將 AggregateFunction 類型轉換為明文(類似序列化與反序列區別),而查詢時需要使用 *Merge 函數

SELECTuser_id,anyLastMerge(last_visit_date) AS last_visit_date,sumMerge(cost) AS cost,maxMerge(max_dwell_time) AS max_dwell_time,minMerge(min_dwell_time) AS min_dwell_time
FROM tbl_agg
GROUP BY user_id
ORDER BY user_id ASCQuery id: 30a237df-6018-42fa-a6a9-1d324e21310d┌─user_id─┬─────last_visit_date─┬─cost─┬─max_dwell_time─┬─min_dwell_time─┐
│ 100002017-10-01 06:00:0035102 │
└─────────┴─────────────────────┴──────┴────────────────┴────────────────┘1 row in set. Elapsed: 0.005 sec.

看到這里是否覺得這種方式過于繁瑣,連正常的數據插入都需要借助 State 函數,那么在升級改造時將寸步難行。好在上面的方式并不是主流的方式,我們可以借助物化視圖來屏蔽 State 過程,讓數據插入保持原生。

1.2 優化體驗

首先我們創建相同結構的普通表作為底表

drop table if exists tbl_agg_basic;
create table if not exists tbl_agg_basic
(`user_id`         String comment '用戶id',`date`            datetime comment '數據灌入日期時間',`city`            String comment '用戶所在城市',`age`             Int8 comment '用戶年齡',`sex`             Int8 comment '用戶性別',`last_visit_date` datetime comment '用戶最后一次訪問時間',`cost`            Int256 comment '用戶總消費',`max_dwell_time`  Int64 comment '用戶最大停留時間',`min_dwell_time`  Int64 comment '用戶最小停留時間'
) engine MergeTreeorder by (user_id, date, city, age, sex);

之后我們將 State 過程寫入物化視圖中

drop table if exists mv_tbl_agg;
create materialized view if not exists mv_tbl_agg to tbl_agg
as
select user_id,date,city,age,sex,anyLastState(last_visit_date) as last_visit_date,sumState(cost)                as cost,maxState(max_dwell_time)      as max_dwell_time,minState(min_dwell_time)      as min_dwell_time
from tbl_agg_basic
group by user_id, date, city, age, sex;

對用戶來說將明細數據優雅的寫入底表中,tbl_agg 對外提供查詢功能,用戶無需關系數據怎么序列化

flow

下面我們只需要假裝什么都不知道向明細數據表插入數據

insert into tbl_agg_basic
values (10000, '2017-10-01', '北京', 20, 0, '2017-10-01 06:00:00', 20, 10, 10),(10000, '2017-10-01', '北京', 20, 0, '2017-10-01 07:00:00', 15, 2, 2),(10001, '2017-10-01', '北京', 30, 1, '2017-10-01 17:05:45', 2, 22, 22),(10002, '2017-10-02', '上海', 20, 1, '2017-10-02 12:59:12', 200, 5, 5),(10003, '2017-10-02', '廣州', 32, 0, '2017-10-02 11:20:00', 30, 11, 11),(10004, '2017-10-01', '深圳', 35, 0, '2017-10-01 10:00:15', 100, 3, 3),(10004, '2017-10-03', '深圳', 35, 0, '2017-10-03 10:20:22', 11, 6, 6);

數據會自動同步到 tbl_agg 中,在查詢時我們只需要面向 tbl_agg 此時會比直接查詢 tbl_agg_basic 有更高的性能

SELECTuser_id,date,city,age,sex,anyLastMerge(last_visit_date) AS last_visit_date,sumMerge(cost) AS cost,maxMerge(max_dwell_time) AS max_dwell_time,minMerge(min_dwell_time) AS min_dwell_time
FROM tbl_agg
GROUP BYuser_id,date,city,age,sex
ORDER BY user_id ASCQuery id: 6f7fd017-9378-4f42-8c20-56bd711487d1┌─user_id─┬────────────────date─┬─city─┬─age─┬─sex─┬─────last_visit_date─┬─cost─┬─max_dwell_time─┬─min_dwell_time─┐
│ 100002017-10-01 00:00:00 │ 北京 │  2002017-10-01 07:00:0035102 │
│ 100012017-10-01 00:00:00 │ 北京 │  3012017-10-01 17:05:4522222 │
│ 100022017-10-02 00:00:00 │ 上海 │  2012017-10-02 12:59:1220055 │
│ 100032017-10-02 00:00:00 │ 廣州 │  3202017-10-02 11:20:00301111 │
│ 100042017-10-01 00:00:00 │ 深圳 │  3502017-10-01 10:00:1510033 │
│ 100042017-10-03 00:00:00 │ 深圳 │  3502017-10-03 10:20:221166 │
└─────────┴─────────────────────┴──────┴─────┴─────┴─────────────────────┴──────┴────────────────┴────────────────┘6 rows in set. Elapsed: 0.008 sec.

還可以插入幾條數據來觀察 tbl_agg 的結果是否符合我們定義的聚合語意

二、SimpleAggregateFunction

對于上面的案例其實在查詢時依然不方便需要調用 Merge 函數,本質因為 AggregateFunction 使用二進制存儲。如果數據以明文存儲是不是就不需要這么麻煩,clickhouse 針對這類場景提供了 SimpleAggregateFunction

drop table if exists tbl_agg_s;
create table if not exists tbl_agg_s
(`user_id` String comment '用戶id',`date`    datetime comment '數據灌入日期時間',`city`    String comment '用戶所在城市',`age`     Int8 comment '用戶年齡',`sex`     Int8 comment '用戶性別',`last_visit_date` SimpleAggregateFunction(anyLast,datetime) comment '用戶最后一次訪問時間',`cost` SimpleAggregateFunction(sum, Int256) comment '用戶總消費',`max_dwell_time` SimpleAggregateFunction(max,Int64) comment '用戶最大停留時間',`min_dwell_time` SimpleAggregateFunction(min,Int64) comment '用戶最小停留時間'
) engine AggregatingMergeTree()order by (user_id, date, city, age, sex);

此時該模型就可以視為完美復刻了 doris 的聚合模型,因為插入和查詢將變得原生化

insert into tbl_agg_s
values (10000, '2017-10-01', '北京', 20, 0, '2017-10-01 06:00:00', 20, 10, 10),(10000, '2017-10-01', '北京', 20, 0, '2017-10-01 07:00:00', 15, 2, 2),(10001, '2017-10-01', '北京', 30, 1, '2017-10-01 17:05:45', 2, 22, 22),(10002, '2017-10-02', '上海', 20, 1, '2017-10-02 12:59:12', 200, 5, 5),(10003, '2017-10-02', '廣州', 32, 0, '2017-10-02 11:20:00', 30, 11, 11),(10004, '2017-10-01', '深圳', 35, 0, '2017-10-01 10:00:15', 100, 3, 3),(10004, '2017-10-03', '深圳', 35, 0, '2017-10-03 10:20:22', 11, 6, 6);select * from tbl_agg_s;

從名字也可以看出,相對 AggregateFunction 就不是那么通用即支持的聚合類型相對較少:

  • any
  • anyLast
  • min
  • max
  • sum
  • sumWithOverflow
  • groupBitAnd
  • groupBitOr
  • groupBitXor
  • groupArrayArray
  • groupUniqArrayArray
  • sumMap
  • minMap
  • maxMap

但這些其實已經夠用了,同時在上面的聚合場景下 SimpleAggregateFunction 會有更高的性能。

提問: 為什么沒有 count

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/718368.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/718368.shtml
英文地址,請注明出處:http://en.pswp.cn/news/718368.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring-靜態代理VS動態代理/實現代理ProxyFactory

文章目錄 靜態代理VS動態代理Spring實現代理ProxyFactory 工作中遇到問題整理動態代理異常com.sun.proxy.$Proxy0 cannot be cast to 靜態代理VS動態代理 靜態代理VS動態代理 參考URL: https://blog.csdn.net/qq_25881443/article/details/103245938 【java項目實戰】代理模式…

【C語言】剖析qsort函數的實現原理

主頁:17_Kevin-CSDN博客 專欄:《C語言》 本文將從回調函數,qsort函數的應用,qsort函數的實現原理三個方面進行講解,請自行跳轉至相對位置進行閱讀~ 目錄 回調函數 qsort函數的應用 qsort函數實現原理 回調函數 什…

mysql主從庫Slave_SQL_Running: No問題經驗分享

最近在創建mysql主從庫的時候,遇到一個問題。執行 mysql> SHOW SLAVE STATUS\G結果顯示 Slave_IO_Running: Yes Slave_SQL_Running: No 很是苦惱,查詢了很久沒有解決 執行 mysql> SELECT * FROM performance_schema.replication_applier_status_…

獨立游戲《星塵異變》UE5 C++程序開發日志1——項目與代碼管理

寫在前面:本日志系列將會向大家介紹在《星塵異變》這款模擬經營游戲,在開發時用到的與C相關的泛用代碼與算法,主要記錄UE5C與原生C的用法區別,以及遇到的問題和解決辦法,因為這是我本人從ACM退役以后第一個從頭開始的項…

代碼隨想錄算法訓練營第五十天 | 買股票2

目錄 買賣股票的最佳時機III買賣股票的最佳時機IV LeetCode 123.買賣股票的最佳時機III LeetCode 123.買賣股票的最佳時機IV 買賣股票的最佳時機III 給定一個數組,它的第 i 個元素是一支給定的股票在第 i 天的價格。 設計一個算法來計算你所能獲取的最大利潤。…

牛客周賽 Round 35(A,B,C,D,E,F,G)

這場簡單,甚至賽時90分鐘不到就AK了。比賽鏈接,隊友題解友鏈 剛入住學校監獄,很不適應,最近難受的要死,加上最近幾場CF打的都不順利,san值要爆掉了,只能慢慢補題了。 這場C是個滑動窗口&#…

冒泡排序 和 qsort排序

目錄 冒泡排序 冒泡排序部分 輸出函數部分 主函數部分 總代碼 控制臺輸出顯示 總代碼解釋 冒泡排序優化 冒泡排序 主函數 總代碼 代碼優化解釋 qsort 排序 qsort 的介紹 使用qsort排序整型數據 使用qsort排序結構數據 冒泡排序 首先,我先介紹我的冒泡…

模糊搜索小案例

C#窗體實現數據錄入與模糊搜索小案例 記錄一下 主要代碼 private void button1_Click(object sender, EventArgs e){string name textBox1.Text;string hometown textBox4.Text;string school textBox6.Text;string sex textBox5.Text;string lat textBox3.Text;string …

c#打印BarTend標簽提示:具名數據源沒有cuckoo*具名數據(解決)

c#打印BarTend標簽提示:具名數據源沒有cuckoo*具名數據(解決) 今天咕咕更新打印模板的時候遇到的問題,就是在模版中配置了字段名,但是啟動c#應用,后端發送json數據打印的時候c#報錯提示,沒有在…

python 小游戲《2048》字符版非圖形界面

參考鏈接: 閑談2048小游戲和數組的旋轉及翻轉和轉置 目錄 2048 一、方陣類 二、隨機插入1或2 三、 合并和遞增 四、 判斷和移動 五、 鍵盤控制 完整源代碼 玩法過程 2048 上回說到2048小游戲中數組的各種旋轉、翻轉的方法,就是為代碼編程作準…

第十六天-爬蟲selenium庫

目錄 1.介紹 2.使用 selenium 1.安裝 2.使用 1.測試打開網頁,抓取雷速體育日職乙信息 2.通過xpath查找 3.輸入文本框內容 send_keys 4.點擊事件 click 5.獲取網頁源碼: 6.獲取cookies 7.seleniumt提供元素定位方式:8種 8.控制瀏覽…

Spring Security OAuth2如何自定義返回的 Token 信息

文章目錄 Spring Security OAuth2如何自定義返回的 Token 信息定制不透明令牌的信息Springsecurity-oauth2之TokenEndPoint參考Spring Security OAuth2如何自定義返回的 Token 信息 Spring Boot+OAuth2,如何自定義返回的 Token 信息? 參考URL: https://www.jianshu.com/p/b7…

【Go】指針的聲明和初始化

package mainimport "fmt"func main() {// 聲明一個整數變量var num int 42// 聲明一個指向整數的指針變量,并將其初始化為指向整數變量的地址var ptr *int &num// 打印整數變量的值和指針變量的值(即整數變量的地址)fmt.Pri…

2024第24屆中國國際工業博覽會新能源與智能網聯汽車展電池制造展館

2024第24屆中國國際工業博覽會新能源與智能網聯汽車展電池制造展館 時間:2024年9月24日-28日 地點:國家會展中心(上海) 主辦單位:工業和信息化部、國家發展和改革委員會、科學技術部、商務部、中國科學院、中國工程…

【游記】GDOI2024

GDOI2024游記 老年退役選手。NOIP 218 分,GDOI 純純旅游。 Day -5 周日返校,開始停課。 開始攢 rp。 Day -4 模擬賽,犯困,啥也不會。 下午打球。 Day -3 模擬賽,不困,還是啥也不會。 下午打球。 …

CSS3單獨制作移動端頁面布局方式(流式布局、flex彈性布局)

目錄 1. 流式布局(百分比布局)2. flex彈性布局(強烈推薦)2.1 介紹2.2 Flex容器常見屬性2.2.1 flex-direction2.2.2 justify-content2.2.3 flex-wrap2.2.4 align-items2.2.5 align-content2.2.6 flex-flow 2.3 Flex項目常見屬性2.3.1 flex2.3.2 align-self和order 1. 流式布局(百…

銀河麒麟之Workstation安裝

一、VMware Workstation簡介 VMware Workstation是一款由VMware公司開發的虛擬化軟件,它允許用戶在一臺物理計算機上運行多個操作系統,并在每個操作系統中運行多個虛擬機。VMware Workstation提供了一個可視化的用戶界面,使用戶可以輕松創建、…

程序環境和預處理(2)

文章目錄 3.2.7 命名約定 3.3 #undef3.4 命令行定義3.5 條件編譯3.6 文件包含3.6.1 頭文件被包含的方式3.6.2 嵌套文件包含 4. 其他預處理指令 3.2.7 命名約定 一般來講函數和宏的使用語法很相似,所以語言本身沒法幫我們區分二者,那我們平時的一個習慣是…

linux條件判斷之if-then

if..then是最常見的條件判斷語句,簡而言之,就是當符合某個條件判斷的時候,就予以進行某項工作。 1.if-then格式 if-then格式1: if [ 條件判斷表達式 ];then 當條件判斷表達式成立時,需執行的命令 fi if-then格式2…

Redis安全加固策略:綁定Redis監聽的IP地址 修改默認端口 禁用或者重命名高危命令

Redis安全加固策略:綁定Redis監聽的IP地址 & 修改默認端口 & 禁用或者重命名高危命令 1.1 綁定Redis監聽的IP地址1.2 修改默認端口1.3 禁用或者重命名高危命令1.4 附:redis配置文件詳解(來源于網絡) 💖The Beg…