前言
最近公司選用clickhouse體系作爲數據解決方案,ck由於底層存儲區別hadoop函數,導致hql一些很好用的特性無法按照之前的寫法來實現,比如按分區設行號,first_value(),lag()等開窗函數也無法正常使用,這也直接影響了我們實現業務的效率,可能導致直接懵逼…這不趁着週末來研究一番ck特殊語法。以保證以後快速從ck中找出慣用的hql邏輯的替代方案。雖然目前ck已經也開始有自己的窗口函數,不過相對hive來說還有待完善。
不過既然選擇了ck,那麼新的學習成本也是有的,查詢方面它也並不是那麼一無是處,必須花點精力理解下它特有的函數,也許我們就會醍醐灌頂,找出較好的替代解決思路。在理解ck一些函數特性後,我也發現hql的開窗函數ck也是可以通過一些邏輯來實現的。第一節就從分區設置行號說起吧。。ck裏面有行號函數,但是隻能是全局的rowNumberInAllBlocks()
不滿足需求,不要看這個需求簡單,實際用到的地方可不會少。
準備
- 建表
CREATE TABLE user_log -- 用戶消費日誌
(
uid String, -- 唯一id
value Int32 -- 金額
)
ENGINE = MergeTree PARTITION BY uid order by uid;
- 插數
insert into user_log
values
('A',100),
('B',400),
('D',600),
('A',50),
('D',400),
('A',2000);
- 需求
下面說下我們需求,就是按用戶分組,根據每個用戶的消費記錄,按金額從大到小排序後分別設置行號。
邏輯
下面到關鍵的查詢了,這裏會用到groupArray() 、arrayEnumerate()
這個兩個聚合函數以及array join
語法。函數不清楚的可以參考官網。邏輯上理解:就是先分組,用groupArray
將每組的value構造出一個數組,然後獲取數組中元素下標,最後用array join
將元素和下標都讀出來。好了話不多說上代碼。
代碼
select
uid,
value,
row_number
from(
select
uid,
groupArray(value) as value_list,
arrayEnumerate(value_list) as index_list
from(
select *
from user_log
order by value desc
)
group by uid
)array join value_list as value,
index_list as row_number
order by uid;
查詢結果:
-------------------
┌─uid─┬─value─┬─row_number─┐
│ A │ 2000 │ 1 │
│ A │ 100 │ 2 │
│ A │ 50 │ 3 │
│ B │ 400 │ 1 │
│ D │ 600 │ 1 │
│ D │ 400 │ 2 │
└─────┴───────┴────────────┘
6 rows in set. Elapsed: 0.010 sec.
結尾
結果和我們想要的是一致的。行號只是衆多需求中的一個,重點是對ck特有函數的學習,如果你真的理解了groupArray,arrayMap ...
等聚合函數的用法,那麼你已經掌握了ck的一項利器了!