背景
在进行报表分析汇总的时候,如果数据量比较大都会采用分而治之的原则。就是将大的时间范围,拆分为小的时间范围。也就是我们日常所说的预聚合。ClickHouse提供了Aggregating引擎,以增量的方式进行数据聚合。该引擎继承自 MergeTree,并改变了数据片段的合并逻辑。ClickHouse 会将一个数据片段内所有具有相同主键(准确的说是 排序键)的行替换成一行,这一行会存储一系列聚合函数的状态。预聚合的业务场景大体可以分为如下三部分:
瞬时值的预聚合
以设备为例,比如:设备的状态、最新的上报指标等。这些都是瞬时值,如果采用OLTP型的数据库,我们会在设备表中增加相应的字段,记录最新的数据。或者通过Redis等nosql数据库将相关信息进行缓存。OLAP数据库不太擅长更新,可以通过预聚合的方式来实现瞬时值的存储。以CH为例,可以使用Aggregating来实现。借助于anyLast函数,设备最近告警的聚合表示例如下:
CREATE TABLE dws_device_xxx
(
`product_key` String, `device_key` String,
`device_key` String,
`last_alarm` SimpleAggregateFunction(anyLast,Array(Nullable(String))),
`rpt_time` DateTime64(3),
...
)ENGINE = ReplicatedAggregatingMergeTree('/clickhouse/tables/{layer}-{shard}/dws_device_xxx','{replica}')
ORDER BY (product_key,device_key)
SETTINGS index_granularity = 8192;
SimpleAggregateFunction比AggregateFunction具有相同聚合功能,但是性能更好。
可以累计的预聚合
将函数f应用于行集的结果S1 UNION ALL S2,可以通过f单独应用于行集的部分来获得,然后再次应用于f结果:f(S1 UNION ALL S2) = f(f(S1) UNION ALL f(S2))。典型的指标比如:设备告警次数、用户访问次数等。都是可以通过增量累加的方式来实现指标的计算。
...
`total_alarm_num` SimpleAggregateFunction(sum,Nullable(Int64)),
...
需要滤重的预聚合
有些指标是无法进行直接的累加的,比如:用户数、设备数这些。以设备数指标为例:一般来说我们都会通过临时表的方式来解决,以增量的方式将设备信息插入到临时表中,最后进行滤重统计来计算设备数。在ClickHouse中,我们可以借助bitmap类型来进行滤重计算。使用bitmap可以大大减少数据占用的空间。以统计在线设备状态为例:将每个设备的状态标识(0离线,1在线),存储在bitmap中,每个设备的状态值只占1bit。
...
`user_ids` AggregateFunction( groupBitmap, UInt(8|16|32|64)) ,
...
聚合函数的中间状态,可以通过聚合函数名称加-State后缀的形式得到它。与此同时,当您需要访问该类型的最终状态数据时,您需要以相同的聚合函数名加-Merge后缀的形式来得到最终状态数据。
尾记
借助于AggregateFunction引擎来进行增量预聚合,非常适合数据量非常大的场景。基本上能满足我们日常的业务需求。
网友评论