张子阳的博客

首页 读书 技术 店铺 关于
张子阳的博客 首页 读书 技术 关于

clickhouse中使用ReplacingMergeTree表引擎

2022-03-19 张子阳 分类: 大数据处理

在上一篇文章 clickhouse中使用Join表引擎 中,我们利用Join表引擎自动排重的特性,实现了在数据插入过程中,基于某些字段只取首行。常见的使用场景,例如:针对用户订单表,查询:用户的首次付款金额、首次订单号。但Join表无法实现取最后一行,例如用户最后一次付款金额、最后一次订单号。这篇文章介绍使用使用ReplacingMergeTree表引擎,来获取最后一次数据插入的行。

准备工作

和前一章类似,我们先做一些数据准备,创建一张基础数据表,user_order用户订单表:

drop table if exists user_order;
create table user_order
(    
    user_id String,         // 用户ID
    event_date String,      // 付款日期
    order_no String,        // 订单号
    amount Int32            // 金额
) ENGINE = MergeTree()
ORDER BY (user_id, event_date)

创建基于ReplacingMergeTree表引擎的物化视图

ReplacingMergeTree表引擎,可以基于排序列进行去重,但是和Join的去重模式不同,它会用最后一次接收的值,去覆盖前面的值。利用这一特性,就可以实现“获取分组后的最后一行数据”这一效果。

drop view if exists user_order_r;
CREATE MATERIALIZED VIEW user_order_r
ENGINE = ReplacingMergeTree()
ORDER BY(user_id)
POPULATE
AS
select user_id, event_date, order_no, amount
from user_order

接下来,插入测试数据:

insert into user_order(user_id, event_date, order_no, amount)
values('user1', '2022-01-01', 'B', 4);
insert into user_order(user_id, event_date, order_no, amount)
values('user1', '2022-01-02', 'C', 8);
insert into user_order(user_id, event_date, order_no, amount)
values('user1', '2022-01-03', 'A', 2);

插入完成后,如果立即对 user_order_r 进行查询,会发现三条数据都存在,这是因为ReplacingMergeTree引擎和AggregatingMergeTree类似,并不是实时执行数据的合并和替换的,而是会有一个不确定的时滞。所以它只是部分地实现了“获取分组最后一行”的效果。

因此,对于user_order_r,还需要进行二次处理,去除重复项。具体的实现方式,可以参考 clickhouse选取group后的首末行。这里我们使用最为简便的AnyLast()函数。

创建user_order_v视图

drop view if exists user_order_v;
CREATE VIEW user_order_v
AS
select user_id, anyLast(event_date) event_date, anyLast(order_no) order_no, anyLast(amount) amount
from (select * from user_order order by user_id, event_date)
group by user_id

这里没有再次创建物化视图,因为数据查询的是 user_order_r,在经历过ReplacingMergeTree合并之后,数据量级通常会缩小很多,优于直接对原始的user_order进行查询。

感谢阅读,希望这篇文章能给你带来帮助!