Clickhouse系列之窗口(Window)函数使用与案例实操

1,700 阅读2分钟

本文正在参加「技术专题19期 漫谈数据库技术」活动

前言

在使用窗口函数之前,我们先来了解一下什么叫做窗口函数(Window function)? 窗口函数在OLAP中使用的十分平常(如 Clickhouse、Hive等数仓),因为它对数据进行实时和离线分析表现都十分优秀。比如:

  • a) 在排名的场景中,我们可以通过窗口函数得到用户的一个积分排名.
  • b) 在TopN场景中,可以获取排名靠前的问题。掘金在热榜中,其实就是用了这个原理,展示点击+阅读中最多的Top20以内的用户文章。

image.png

正文

在了解到什么是窗口函数之后,我们来看看Clickhouse的一个使用。

窗口函数详解

我们来看看Clickhouse的窗口函数有哪些?

窗口函数是否支持
count(*) over (partition by id order by time desc)支持
(count(*) over ()) / 2)支持
select ... from table window w as (partition by id))支持
ROWS frame支持
RANGE frame支持
sum(value) over (order by time)aggregate functions 支持
rank()dense_rank()row_number()支持

它的一个语法格式可以看下面:

select 
aggregate_function (column_name)  
OVER ([[PARTITION BY grouping_column] [ORDER BY sorting_column]  
[ROWS or RANGE expression_to_bound_rows_withing_the_group]] | [window_name])  
FROM table_name  
WINDOW window_name as ([[PARTITION BY grouping_column] [ORDER BY sorting_column])

需要注意的是:

  • PARTITION BY: 它是对数据集进行分组的字段
  • Order by : 它的在聚合函数计算之后进行一个排序操作
  • Window: 允许重复使用窗口函数,所以从语法可以看到窗口在表之后使用了。

案例一使用

  1. 数据准备-创建对应的数据表和库 这个数据包含的是一个分区键、订单id以及订单的值。
CREATE TABLE wf_frame  
(  
`part_key` UInt64,  
`value` UInt64,  
`order` UInt64  
)  
ENGINE = Memory;  
  
INSERT INTO wf_frame FORMAT Values  
(1,1,1), (1,2,2), (1,3,3), (1,4,4), (1,5,5);

image.png 2.BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING使用 我们执行下面的sql:

SELECT  
part_key,  
value,  
order,  
groupArray(value) OVER (PARTITION BY part_key ORDER BY order ASC  
Rows BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS frame_values  
FROM wf_frame  
ORDER BY  
part_key ASC,  
value ASC;

3、现在我们执行一个没有bound和order的sql:

SELECT  
part_key,  
value,  
order,  
groupArray(value) OVER (PARTITION BY part_key) AS frame_values  
FROM wf_frame  
ORDER BY  
part_key ASC,  
value ASC;

案例二使用

背景:加入我们需要实现Hive的窗口函数row number的效果 1、创建库表

CREATE TABLE default.row_number
(
    `user_id` String,
    `user_phone` String,
    `create_time` DateTime,
    `update_time` DateTime
)
ENGINE = MergeTree
ORDER BY user_id
SETTINGS index_granularity = 8192;

image.png 2、我们使用groupArray和groupby、orderby来实现,这个相比于直接使用row number来说是繁琐了点,但是这种方式实现是可以满足业务需求的。

select user_id, 
      groupArray(1)(user_phone) AS user_phone,
      groupArray(1)(create_time) AS create_time,
      groupArray(1)(update_time) AS update_time
 from (select user_id, 
              user_phone,
              create_time,
               update_time
         from default.row_number
        ORDER BY update_time desc
       ) a
group by user_id
order by user_id

image.png

总结

本节主要是对CLickhouse的窗口函数的使用,当然还有一些不足的地方,我们可以去看看其他的博客和官方。我这里只是纪录自己在工作中遇到的问题,然后自己去模拟生产数据进行实践测试。