10.CollapsingMergeTree
10.1.CollapsingMergeTree
10.2.案例(State行和Cancel行匹配示例)
10.3.示例2:聚合查询
10.4.示例3:Cancel状态行取反的聚合查询

10.CollapsingMergeTree

10.1.CollapsingMergeTree

1、在排序键(ORDER BY)的所有字段都相同的条件下,如果特定的字段具有1和-1的值,CollapsingMergeTree将异步删除(折叠)成对的行。没有配对的行将保留。
2、能显著降低存储空间并提升SELECT查询的效率。
3、变相的实现了数据的更新和删除逻辑。

指定表引擎:
CollapsingMergeTree(sign)
参数:sign,标识行类型的列名称,1是状态行,-1是取消行。列的数据类型是Int8。

使用特定的列Sign,如果Sign=1,则表示该行是对象的状态,称之为"状态"行。如果Sign=-1,则表示取消具有属性的对象的状态,称之为"取消"行。

例如,计算用户在某个站点访问的页面数以及停留的时长。在某个时刻,将用户的活动状态写入下面的行:

一段时间后,将用户活动的变化写入以下两行:

第一行取消对象(用户)的先前状态,它应该复制被取消状态行的排序键字段,字段sign设置为-1标 识取消状态。
第二行包含当前状态
取消状态的行包含:排序键字段的拷贝和相反的Sign值。 取消状态的行增加了存储的大小,但是却可以 快速写入数据。

合并算法
当ClickHouse合并数据片段时,具有相同排序键的每一组连续行被缩减为不超过两行,一行的Sign=1, 另一行的Sign=-1。换句话说,条目将折叠。

  1. 如果”state”行与”cancel”行的数目匹配,且最后一行是”state”行,则保留第一个”cancel”和最后一个”state”行。
  2. 如果”state”行比”cancel”行的数目多,则保留最后一个”state”行。
  3. 如果”cancel”行比”state”行的数目多,则保留第一个”cancel”行。
  4. 其它情况,不保留行。

Note:当”state”行比”cancel”行数目至少多2个,或者”cancel”行比”state”行多至少2个时,合并将继续,但是ClickHouse将此情况视为逻辑错误并将其在server的日志记录下来。如果同一份数据被插入了多次,则会发生此错误。

聚合统计
合并算法不能保证所有具有相同排序键的行都位于相同的结果数据片段中,甚至位于同一个物理服务器上。 ClickHouse使用多线程处理SELECT查询,并且无法预测结果中的行顺序。如果需要从CollapsingMergeTree表中完全”折叠”数据,则需要结合Sign字段使用聚合。

例如:计算使用,使用sum(Sign)而不是count()。计算sum,使用sum(Sign * x)而不是sum(x),以此类推。
并且需要添加HAVING sum(Sign) > 0.

聚合的count、sum和avg可以通过这种方式计算,如果一个对象的至少一个状态未折叠,则可以计算聚合 uniq。无法计算聚合的最小值和最大值,因为CollapsingMergeTree不会保存折叠状态的历史记录。

如果要提取数据但不想使用聚合,则可以对FROM子句使用FINAL修饰符,这种方法效率明显不高。

10.2.案例(State行和Cancel行匹配示例):

示例:State行和Cancel行匹配示例
验证:如果"state"行与"cancel"行的数目匹配,且最后一行是"state"行,则保留第一个"cancel"行和最后一个"state"行。

建表语句:

CREATE TABLE UAct
(UserID UInt64,PageViews UInt8,Duration UInt8,Sign Int8
)
ENGINE = CollapsingMergeTree(Sign)
ORDER BY UserID;

首先清空表:

truncate table UAct;

执行如下的数据插入语法:

INSERT INTO UAct VALUES (4324182021466249494, 1, 11, -1),(4324182021466249494, 2, 12, -1);
INSERT INTO UAct VALUES (4324182021466249494, 3, 13, 1);
INSERT INTO UAct VALUES (4324182021466249494, 4, 14, 1);

查看数据:

xxxx2 :) select * from UAct;SELECT *
FROM UAct┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         4 │       14 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         1 │       11 │   -1 │
│ 4324182021466249494 │         2 │       12 │   -1 │
└─────────────────────┴───────────┴──────────┴──────┘
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         3 │       13 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘4 rows in set. Elapsed: 0.010 sec. xxxx2 :)

执行计划外的片段合并操作:

xxxx2 :) optimize table UAct;OPTIMIZE TABLE UActOk.0 rows in set. Elapsed: 0.004 sec. xxxx2 :) select * from UAct;SELECT *
FROM UAct┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         1 │       11 │   -1 │
│ 4324182021466249494 │         4 │       14 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘2 rows in set. Elapsed: 0.008 sec. xxxx2 :)

从示例中可以观察到,最终的数据片段保留了第一个"cancel"行和最后一个"state"行。

10.3.示例2:聚合查询

示例数据:

┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         5 │      146 │    1 │
│ 4324182021466249494 │         5 │      146 │   -1 │
│ 4324182021466249494 │         6 │      185 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘

建表:

DROP TABLE UAct;
CREATE TABLE UAct
(UserID UInt64,PageViews UInt8,Duration UInt8,Sign Int8
)
ENGINE = CollapsingMergeTree(Sign)
ORDER BY UserID;

插入数据:
INSERT INTO UAct VALUES (4324182021466249494, 5, 146, 1);
INSERT INTO UAct VALUES (4324182021466249494, 5, 146, -1),(4324182021466249494, 6, 185, 1);

上面执行了两个INSERT语句,创建了两个不同的数据片段。如果使用一个INSERT语句,ClickHouse将创建一个数据片段,并且将永远不会执行任何合并。
查询数据:

xxxx2 :) select * from UAct;SELECT *
FROM UAct┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         5 │      146 │   -1 │
│ 4324182021466249494 │         6 │      185 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         5 │      146 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘3 rows in set. Elapsed: 0.012 sec. xxxx2 :)

通过两个INSERT语句,创建了两个数据片段。SELECT查询是在两个线程中执行的,我们得到了随机顺序的行。由于尚未合并数据片段,折叠还未发生。
我们无法预测ClickHouse在何时执行数据片段的合并。因此,我们需要使用聚合:

SELECTUserID,sum(PageViews * Sign) AS PageViews,sum(Duration * Sign) AS Duration
FROM UAct
GROUP BY UserID
HAVING sum(Sign) > 0;

如果不使用聚合,可以对FROM子句使用FINAL修饰符进行强制合并:

select * from UAct FINAL;

效果如下:

xxxx2 :) select * from UAct FINAL;SELECT *
FROM UAct
FINAL┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         6 │      185 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘1 rows in set. Elapsed: 0.010 sec. xxxx2 :)

10.4.示例3:Cancel状态行取反的聚合查询

示例数据:

┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         5 │      146 │    1 │
│ 4324182021466249494 │        -5 │     -146 │   -1 │
│ 4324182021466249494 │         6 │      185 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘

这个方法的核心思想是仅考虑关键字段,在"cancel"行中,可以指定负数,这些负数的值等于行的前一个版本的关键字段值的取反,这样在求和时就可以不使用Sign列。对于这种方法,必须更改PageViews和Duration字段的数据类型,从UIn8改成Int16。

CREATE TABLE UAct
(UserID UInt64,PageViews Int16,Duration Int16,Sign Int8
)
ENGINE = CollapsingMergeTree(Sign)
ORDER BY UserID;

插入数据,并测试:

insert into UAct values(4324182021466249494,  5,  146,  1);
insert into UAct values(4324182021466249494, -5, -146, -1);
insert into UAct values(4324182021466249494,  6,  185,  1);

11_CollapsingMergeTree,(State行和Cancel行匹配示例),聚合查询,Cancel状态行取反的聚合查询相关推荐

  1. ElasticSearch聚合查询返回结果buckets取值

    ElasticSearch聚合查询返回结果buckets取值 1.聚合查询如下: {"size":0,"query":{"bool":{&q ...

  2. excel 首行下示例格式_Excel条件格式示例

    excel 首行下示例格式 This week, there were a couple of Excel conditional formatting questions in the blog c ...

  3. pandas处理数据代码:分组聚合、保留重复行、删除重复行

    txt转csv import numpy as np import pandas as pdtxt=np.loadtxt('1216.txt')txtDF=pDataFrame(txt) txtDF. ...

  4. python非贪婪、多行匹配正则表达式例子[转载]

    python非贪婪.多行匹配正则表达式例子[转载] 一些regular的tips: 1 非贪婪flag >>> re.findall(r"a(\d+?)", &q ...

  5. 传递命令行参数示例代码 (C 和 Python)

    C语言 在 C 语言中, 使用 main 函数的输入参数 argc 和 argv 传入命令行参数. argc 为 int 类型, 表示传入命令行参数的个数 (argument count); argv ...

  6. python字符串与文本处理技巧(2):大小写敏感搜索、最短匹配、多行匹配、Unicode标准化

    1. 字符串忽略大小写的搜索替换 re.findall(patter, string, flags=re.IGNORECASE) 当我们需要忽略字符串中的字母大小写进行模式搜索时可以采用如下方案: i ...

  7. SELECT执行过程,MySQL聚合函数,多行分组函数,GROUP BY HAVING,详细完整可收藏

    文章目录 1.聚合函数介绍 2.五个常用聚合函数 3.GROUP BY 4.HAVING 5.SELECT的执行过程 1.聚合函数介绍 聚合函数作用于一组数据,并对一组数据返回一个值.聚合函数不能嵌套 ...

  8. 《Python Cookbook 3rd》笔记(2.8):多行匹配模式

    多行匹配模式 问题 你正在试着使用正则表达式去匹配一大块的文本,而你需要跨越多行去匹配. 解法 这个问题很典型的出现在当你用点 (.) 去匹配任意字符的时候,忘记了点 (.) 不能匹配换行符的事实.比 ...

  9. python非贪婪匹配_Python中关于正则表达式非贪婪以及多行匹配功能详解

    这篇文章主要介绍了Python正则表达式非贪婪.多行匹配功能,结合实例形式分析了Python正则表达式中非贪婪及多行匹配功能的实现方法与相关注意事项,需要的朋友可以参考下 本文实例讲述了Python正 ...

最新文章

  1. 应用程序异常管理组件 Example 程序
  2. Python入门100题 | 第074题
  3. 蓝桥杯练习系统习题解答-入门训练
  4. 《税务登记管理办法》
  5. csharp为何不流行_【经营】做餐饮,算好加减法,你不赚谁赚
  6. 集合均值(逆元+数学)
  7. springboot忽略证书_SpringBoot获取resource下证书失败
  8. 垂直串联六关节机器人调试手册_工业机器人有哪些应用你知道吗?
  9. 网页图表Highcharts实践教程之图表代码构成
  10. nohup命令导致nohup.out文件过大处理办法
  11. 封装mysql数据库操作系统_封装MySQL的单例,连接数据库并对数据进行增删改查操作...
  12. java csv下载_javacsv.jar
  13. 东芝服务器报错误代码维修,东芝复印机错误代码和维修代码
  14. java基础之String类型
  15. 电驴无法增加服务器怎么办,电驴连接不上服务器怎么办?
  16. 数独问题流程图_数独游戏的难度等级分析及求解算法研究
  17. vue中使用canvas手写输入识别中文
  18. 计算机通过网口连接网络,使电脑连接网络的方法
  19. MATLAB实现雅可比与高斯塞德尔迭代
  20. “逐梦太空,情系北斗” 北斗导航技术与产业应用

热门文章

  1. Python中的函数递归
  2. wxWidgets:wxContextHelp类用法
  3. boost::future相关的测试程序
  4. boost::math模块使用barycentric有理插值的测试程序
  5. boost::intrusive::list_base_hook用法的测试程序
  6. boost::log::formatting_ostream用法的测试程序
  7. boost::hana::one用法的测试程序
  8. boost::filesystem模块和boost::timer混合的测试程序
  9. GDCM:gdcm::TagPath的测试程序
  10. GDCM:DICOM文件的输入和输出流测试程序