ClickHouse 新特性 Live View 体验
Posted DataFlow范式
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ClickHouse 新特性 Live View 体验相关的知识,希望对你有一定的参考价值。
今天笔者来聊一聊 ClickHouse 中的一个新特性,即 Live View 表。
MA(Moving Average)
提到 MA,估计大家最先想到的应该是 Marketing Automation,因为在 DT 时代,自动化营销在大数据领域应用非常广泛。
但是,笔者今天要讲的 MA,其实是在机器学习中普遍使用的 Moving Average,滑动平均。
那么什么是 Moving Average ?
请君为我倾耳听。
含义
MA(Moving Average)字面意思就是滑动平均,用来衡量当前趋势的方向。MA 经常被用于金融领域的预测,一旦计算出一个平均值结果,就会绘制成图标,以便交易员能够查看滑动的数据,而不是聚焦于所有金融市场固有的每日价格波动。
在实际应用场景中,有两种基本且常用的 MA:
SMA(Simple Moving Average)
简单滑动平均模型,通过计算过去数据集的平均值。在金融场景下,一组数字或者价格被加在一起,然后除以该集合价格的数量。EMA(Exponential Moving Average)
指数滑动平均,赋予最近的价格更多的权重,以使它对新的信息更有反应。
MA 最常见的应用是确定趋势方向并确定支撑位和阻力位。虽然 MA 本身已经足够有用的,但它们也构成了其他技术指标的基础,如 MACD(移动平均线收敛散度),是不是很熟悉了,MACD 指标是所有技术指标里最经典的一个技术指标,在股市币圈随处可见的曲线图。
Live View
在数据分析中,分析师经常使用 MA 以确定长期趋势。ClickHouse 新版本中提供 Live View 表来实现 MA 实时计算功能,类似流计算。
Live View 表的应用场景之一是对事件数据进行实时指标的计算。事件数据流包括来自 IoT 传感器的读数、来自证券交易所的价格波动或来自生产服务器的某些指标。ClickHouse 可以以良好的压缩率存储所有这些数据以及提供出色的分析查询性能。
在本文中,笔者将使用 Live View 对事件流进行简单的实时统计,然后将其连续地加载到 ClickHouse 表中。
基于 Docker 部署 ClickHouse
目前 Live View 还处于实验阶段,experimental feature,如果要使用的话,需要开启 allow_experimental_live_view,否则报错如下错误:
DB::Exception: Experimental LIVE VIEW feature is not enabled (the setting 'allow_experimental_live_view').
使用之前需要设置:
set allow_experimental_live_view=1
所以,为了方便读者更好地体验 Live View 表来计算事件流的实时统计信息,笔者将使用 Docker 部署 ClickHouse 20.1.x 的最新稳定版本(确保版本不低于 20.1.2.4)。
下载镜像
$ docker pull yandex/clickhouse-server:20.1.7.38
$ docker pull yandex/clickhouse-client:20.1.7.38
启动 ClickHouse Server
$ docker run -d --name clickhouse-ma --ulimit nofile=262144:262144 yandex/clickhouse-server:20.1.7.38
通过 ClickHouse Client 访问
$ docker run -it --rm --link clickhouse-ma:clickhouse-server yandex/clickhouse-client:20.1.7.38 --host clickhouse-server
ClickHouse client version 20.1.7.38 (official build).
Connecting to clickhouse-server:9000 as user default.
Connected to ClickHouse server version 20.1.7 revision 54431.
bf3b961ffd54 :)
为了方便实验,笔者使用包含 value 和 time 列的表来存储数据流,读者可以基于实际的事件流来进行更好的实验。
在 ClickHouse 中创建表结构:
CREATE TABLE events(`value` Int32, `time` DateTime DEFAULT now())
ENGINE = Memory
最近 N 个值的简单平均值
这里我们来计算一个简单的统计指标,即计算最后 N 个值的平均值。用于计算最后 N 个值的平均值(假设 N 为 10)的查询可以写为:
bf3b961ffd54 :) SELECT sum(value)/10
FROM (
SELECT *
FROM events
ORDER BY time DESC
LIMIT 10
)
写入一些模拟数据:
bf3b961ffd54 :) INSERT INTO events VALUES
(1,now()-9),
(2,now()-8),
(3,now()-7),
(4,now()-6),
(5,now()-5),
(6,now()-4),
(7,now()-3),
(8,now()-2),
(9,now()-1),
(10,now())
查询简单平均值:
bf3b961ffd54 :) SELECT sum(value) / 10
FROM
(
SELECT *
FROM events
ORDER BY time DESC
LIMIT 10
)
┌─divide(sum(value), 10)─┐
│ 5.5 │
└────────────────────────┘
最近 N 个值的 MA
上面我们通过直接查询最后 10 行数据的平均值,返回正确的结果。现在,我们可以创建一个 Live View 表来计算 MA。
首先创建 Live View 表:
bf3b961ffd54 :) SET allow_experimental_live_view=1
bf3b961ffd54 :) CREATE LIVE VIEW ma10 AS
SELECT sum(value) / 10
FROM
(
SELECT *
FROM
(
SELECT *
FROM events
ORDER BY time DESC
LIMIT 10
)
ORDER BY time DESC
LIMIT 10
)
使用如下查询,获得和上面查询相同的结果:
bf3b961ffd54 :) SELECT * FROM ma10
┌─divide(sum(value), 10)─┐
│ 5.5 │
└────────────────────────┘
大家可能已经注意到,用于创建 Live View 表的查询与用于计算平均值的查询不同。在这里,我们有了两个子查询,直观看上去,包装原始子查询的子查询似乎是多余的。
接下来,笔者带着大家深入研究 Live View 表是如何处理子查询。
Live View 如何工作
Live View 表将部分查询结果缓存在内存中,然后将部分结果与新数据合并以产生最终结果。可合并的块(mergeable blocks)存储部分结果,这些是分布式表用来从不同的远程服务器收集部分结果的相同块。对于 Live View 表,我们使用新的可合并块存储最新数据,并将它们与从旧数据中获取的缓存可合并块组合在一起。
因此大家就能够很好地明白为什么上面的 Live View 表中包含两个子查询的道理了。当存储的查询包含子查询时,可合并块仅针对最里面的子查询获得。即对于上面的查询示例,最里面的子查询是
SELECT * FROM events ORDER BY time DESC LIMIT 10
可合并块包含此查询的部分结果。
Live View 实际上如何工作
让我们再看一下上面的示例以了解细节,有助于将 Live View 应用到实际生产数据中:
Live View 表将可合并块存储在内存中
结合来自新旧数据的可合并块,以获得最终结果
当一个具有存储的查询被用于创建 Live View 表,并且该查询具有子查询时,则使用最里面的子查询获取可合并的块
再来看一下这个存储的查询,该查询生成实时 MA 值:
CREATE LIVE VIEW ma10 AS
SELECT sum(value) / 10
FROM
(
SELECT *
FROM
(
SELECT *
FROM events
ORDER BY time DESC
LIMIT 10
)
ORDER BY time DESC
LIMIT 10
)
下面,笔者将逐步分解 Live View 表的工作方式。
步骤 1
Live View 表首先使用 events 表中的当前数据来计算可合并块。如果新数据尚未到达,那么 events 表具有到目前为止的所有数据。因为存储的查询具有子查询,那么 Live View 表使用最里面的查询来获取可合并的块。因此,可合并块包含以下查询的部分结果:
SELECT * FROM events ORDER BY time DESC LIMIT 10
步骤 2
由于没有新数据到达,没有其他可合并块,因此我们拥有了所需的所有可合并块。我们通过将外部查询应用于可合并的块来获得最终结果,其中查询是
CREATE LIVE VIEW ma10 AS
SELECT sum(value) / 10
FROM
(
SELECT *
FROM
(
...
)
ORDER BY time DESC
LIMIT 10
)
当没有新数据时,外部查询中的 ORDER BY time DESC 和 LIMIT 10 不会做任何有用的事情,因为内部的可合并块已经应用了相同的 ORDER BY 和 LIMIT 子句。它们仅在有新数据到达时才起作用,并且我们结合来自新旧数据的可合并块。
步骤 3
假设现在我们有了一个新的 INSERT 操作,ClickHouse 将其分为一个或多个数据块。Live View 分别处理每个块。
对于包含最新数据的数据块,Live View 必须将旧数据的部分结果与新块的数据结合起来。通过前面的讲解,已经知道 Live View 表将旧数据的部分结果存储为可合并块,并将这些块与其他可合并块进行合并。因此,Live View 表从新块中计算出可合并块,然后将这些可合并块与现有块合并。
根据上面的示例,来自旧数据的可合并块有十行,它使用最里面的查询来获取它们。同样,我们使用最里面的查询从新块中获取可合并的块,并且它最多也可以包含十行。当我们将来自旧数据和新数据的这些可合并块组合在一起时,最终可能多达二十行。但是我们只想要十行数据,这就是为什么我们在外部子查询中还有另一个 ORDER BY time DESC 和 LIMIT 10 来过滤掉不需要的原因了。
步骤 4
一旦我们将 ORDER BY time DESC 和 LIMIT 10 子句应用于可合并块后,我们只需像以前一样计算平均值并可获得所需的结果。此时,我们就有了一个实时 MA,因为每个新数据块都会重复该过程进行计算。
实时 MA
对 ClickHouse 的 Live View 有了新的认识后,我们将准备查看实时的 MA 数据。
打开另一个 ClickHouse 客户端,我们将使用它来插入数据并在当前客户端中执行 WATCH 查询,以观察实时 MA。
1. 客户端 client1
client1 :) WATCH ma10
┌─divide(sum(value), 10)─┬─_version─┐
│ 5.5 │ 1 │
└────────────────────────┴──────────┘
↙ Progress: 1.00 rows, 16.00 B (9.70 rows/s., 155.17 B/s.)
此时客户端 client1 处于实时监控和查询状态。
2. 客户端 client2
启动并登录客户端 client2,插入数据 1:
client2 :) INSERT INTO events (value) VALUES (1)
由于计算结果相同,即:
sum([2, 3, 4, 5, 6, 7, 8, 9, 10, 1])/10 = 5.5
所以 client1 客户端的 WATCH 查询中的值未更改,所以没有输出结果。
我们继续插入另一个值 1,现在就会看到客户端 client1 输出新的 MA 结果:
bf3b961ffd54 :) WATCH ma10
WATCH ma10
┌─divide(sum(value), 10)─┬─_version─┐
│ 5.5 │ 1 │
└────────────────────────┴──────────┘
┌─divide(sum(value), 10)─┬─_version─┐
│ 5.4 │ 2 │
└────────────────────────┴──────────┘
↓ Progress: 2.00 rows, 32.00 B (0.00 rows/s., 0.03 B/s.)
计算结果为:
sum([3, 4, 5, 6, 7, 8, 9, 10, 1, 1])/10 = 5.4
如果再插入另一个值 1,则应该看到结果更改为:
┌─divide(sum(value), 10)─┬─_version─┐
│ 5.5 │ 1 │
└────────────────────────┴──────────┘
┌─divide(sum(value), 10)─┬─_version─┐
│ 5.4 │ 2 │
└────────────────────────┴──────────┘
┌─divide(sum(value), 10)─┬─_version─┐
│ 5.2 │ 3 │
└────────────────────────┴──────────┘
计算结果为:
sum([4, 5, 6, 7, 8, 9, 10, 1, 1, 1])/10 = 5.2
添加更多的数据就会观察到 Live View 实时展示 MA 数据滑动。
扩展
针对 IOT 传感器等事件数据,可以通过 minifi 等 agent 采集数据,通过 kafka 将事件数据写入 ClickHouse。当然也可以通过 Flink 对实时事件数据进行流计算。
结论
在本文中,我们研究了如何在 Live View 表中使用子查询来计算实时滑动平均值。对于实际的需求,可以使用类似的技术来计算其他实时指标。
参考
https://www.altinity.com/blog/2020/3/9/real-time-moving-average-with-clickhouse-live-views
你若喜欢,点个在看哦
以上是关于ClickHouse 新特性 Live View 体验的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server 2016新特性:Live Query Statistics
clickhouse 发生代码:999 where optimize MATERIALIZED VIEW table with ReplicatedReplacingMergeTree engine