前言
上篇教程介绍了 Apache IoTDB 的基本架构、可部署形态、安装启动方法及数据模型,了解了这些 IoTDB 的基本概念,下面我们就将开始介绍 IoTDB 处理时序数据实现的具体功能和具体的操作命令。
本篇将介绍 Apache IoTDB 可实现的数据导入和查询相关的功能类型和 SQL 语句命令,后篇将介绍 IoTDB 如何实现数据的删除、导出和元数据操作。
1. 导入时间序列
使用 Apache IoTDB,我们可以手动或者自动写入数据,还可以连接终端接收数据。此处先介绍自动导入已有的数据表格的方法。
1.2 IoTDB 的架构
依然以上篇使用的实际工业应用场景为例,我们给出一个测试用的数据表格( CSV 格式),可点击 http://gofile.me/6WI2y/9TstJU5wt 下载,部分数据如下表所示。这是一段时序数据,记载了某集团的 2 号高山风机在某段时间内的轮毂温度。后续的 SQL 命令语句场景均以处理此表的时序数据为例。
1.2 CSV 导入时间序列和值
接下来利用 Apache IoTDB 中 tools 文件夹下的 CSV 工具,可以将 CSV 格式的上表数据导入 IoTDB 中。
首先我们启动 IoTDB server,然后去到 tools 目录,输入指令。Linux 和 Mac 系统下的指令格式为:
import-csv.sh -h <ip> -p <port> -u <username> -pw <password> -f <xxx.csv> [-fd <./failedDirectory>]
复制代码
其中 -f 指定了要导入的数据,如果指定的是文件夹,就会把文件夹中所有的后缀为 TXT 与 CSV 的文件进行批量导入。-fd 指定了一个目录来存放保存失败的文件,如果没有指定这个参数,失败的文件将会被保存到源数据的目录中,文件名为源文件名加上 .failed 的后缀。
假如我将“ TestData.csv ”这个测试数据文件下载到了 usr 文件夹,那么我的导入文件指令则为:
./import-csv.sh -h 127.0.0.1 -p 6667 -u root -pw root -f /usr/TestData.csv -fd ./failed
复制代码
显示“ Import completely! ”则为导入成功。
1.3 SQL 写入序列和值
当前已导入了一张表格,即测试数据 TestData ,这在 Apache IoTDB 中仅为一个存储组中的一条时间序列。为后续学习更多查询操作,除测试数据的时间序列外,此处再创建一条简单的时间序列,并往里面写一个值。
1.3.1 创建单条时间序列
我们可以使用 create timeseries 语句来创建时间序列,SQL 语句为:
create timeseries root.BHSFC.Q1.W003.speed FLOAT encoding=RLE
复制代码
创建时间序列需要指定数据类型和编码方式,这里指定了 FLOAT 和 RLE 。
1.3.2 写入数据
我们可以使用如下 SQL 语句在上条时间序列中写一个值:
insert into root.BHSFC.Q1.W003(timestamp,speed) values(1657468800000,1)
复制代码
timestamp 是时间戳,我们把要写入的时间(此处设定为 2022 年 7 月 11 日 0 点 0 分 0 秒)转换为时间戳 1657468800000 输入,speed 的值写入 1。
1.3.3 创建多条时间序列
我们也可以创建同一设备下的多条时间序列,这里我们按照数据模式往时间序列中插入值,就会自动创建对应的对齐时间序列,SQL 语句为:
insert into root.ln1.wf01(time, status, temperature) aligned values(1657468800000, 0, 1)
复制代码
这样我们就得到了两条属于第二个存储组,共享 1657468800000 这个时间戳,值分别为 0 和 1 的时间序列 root.ln.wf01.status 和 root.ln.wf01.temperature ,加上测试数据 TestData 构成的第一个存储组,完整的数据模式正如下图所示。
了解了导入数据的方法后,接下来我们将介绍 Apache IoTDB 如何实现对时序数据的基本查询功能。基本查询功能可通过两类 SQL 语句实现:select from 语句查询和 where 语句查询。
2. 数据基本查询
2.1 使用 select from 语句查询
2.1.1 查询单个时间序列的数据
查询导入的测试数据中的所有行数据,可使用如下 SQL 语句:
select WROT_HubTmp from root.BHSFC.Q1.W002
复制代码
输出的结果如下(仅截取前 6 行数据):
IoTDB> select WROT_HubTmp from root.BHSFC.Q1.W002+-----------------------------+------------------------------+| Time|root.BHSFC.Q1.W002.WROT_HubTmp|+-----------------------------+------------------------------+|2022-01-11T21:51:40.000+08:00| 14.4||2022-01-11T21:51:54.000+08:00| 14.5||2022-01-11T21:52:01.000+08:00| 14.4||2022-01-11T21:53:56.000+08:00| 14.3||2022-01-11T21:54:14.000+08:00| 14.4|-|2022-01-11T21:56:17.000+08:00| 14.3|
复制代码
查询结果默认显示 1000 行,也可以限制显示的数目,在末尾加上“limit <数目>”即可。如只要显示 10 行,SQL 语句为:
select WROT_HubTmp from root.BHSFC.Q1.W002 limit 10
复制代码
也可以限制起始行数,SQL 语句为:
select WROT_HubTmp from root.BHSFC.Q1.W002 limit 2 offset 2
复制代码
这样查询的结果就会从第三行开始显示,且只显示两个数据:
IoTDB> select WROT_HubTmp from root.BHSFC.Q1.W002 limit 2 offset 2+-----------------------------+------------------------------+| Time|root.BHSFC.Q1.W002.WROT_HubTmp|+-----------------------------+------------------------------+|2022-01-11T05:52:01.000+08:00| 14.4||2022-01-11T05:53:56.000+08:00| 14.3|+-----------------------------+------------------------------+Total line number = 2
复制代码
查询的结果默认按时间由远到近排列,如果我们想要最新的时间显示在前面,则加上 ORDER BY TIME DESC 子句。例如查询最新的五条数据,SQL 语句为:
select WROT_HubTmp from root.BHSFC.Q1.W002 order by time desc limit 5
复制代码
输出的结果如下:
IoTDB> select WROT_HubTmp from root.BHSFC.Q1.W002 order by time desc limit 5+-----------------------------+------------------------------+| Time|root.BHSFC.Q1.W002.WROT_HubTmp|+-----------------------------+------------------------------+|2022-01-15T06:46:40.000+08:00| 16.0||2022-01-15T06:46:28.000+08:00| 15.9||2022-01-15T06:46:02.000+08:00| 16.0||2022-01-15T06:45:56.000+08:00| 15.9||2022-01-15T06:45:50.000+08:00| 16.0|+-----------------------------+------------------------------+Total line number = 5
复制代码
而查询我们用 SQL 语句写入的 speed 时间序列,可使用如下 SQL 语句:
select speed from root.BHSFC.Q1.W003
复制代码
输出的结果如下:
IoTDB> select speed from root.BHSFC.Q1.W003+-----------------------------+------------------------+| Time|root.BHSFC.Q1.W003.speed|+-----------------------------+------------------------+|2022-07-11T00:00:00.000+08:00| 1.0|+-----------------------------+------------------------+Total line number = 1
复制代码
可以看到之前插入时输入的时间戳 1657468800000 自动转换成了时间:2022 年 7 月 11 日 0 点 0 分 0 秒。
2.1.2 查询多个时间序列的数据
如果要查询多个时间序列的数据,可以输入 SQL 语句:
select * from root.BHSFC.** limit 10
复制代码
* 是通配符,可以代替字符,进行模糊查询。在路径中 * 表示一层,** 表示一层或多层。输入上述 SQL 语句,就会显示这两条时间序列 root.BHSFC.Q1.W002.WROT_HubTmp 和 root.BHSFC.Q1.W003.speed 的前十个值,以上的查询结果默认按照时间戳大小升序排列,即日期从远到近。如果要使查询结果按日期从近到远排列,则可输入 SQL 语句:
select WROT_HubTmp from root.BHSFC.Q1.W002 order by time desc
复制代码
2.1.3 查询最新数据
如果要查询指定时间序列的最新数据,可以输入 SQL 语句:
select last WROT_HubTmp from root.BHSFC.Q1.W002
复制代码
查询结果为:
IoTDB> select last WROT_HubTmp from root.BHSFC.Q1.W002+-----------------------------+------------------------------+-----+--------+| Time| timeseries|value|dataType|+-----------------------------+------------------------------+-----+--------+|2022-01-15T06:46:40.000+08:00|root.BHSFC.Q1.W002.WROT_HubTmp| 16.0| DOUBLE|+-----------------------------+------------------------------+-----+--------+Total line number = 1
复制代码
也可以查询多个时间序列的最新值,可使用如下 SQL 语句:
select last * from root.BHSFC.**
复制代码
查询结果为:
ulimitIoTDB> select last * from root.BHSFC.**+-----------------------------+------------------------------+-----+--------+| Time| timeseries|value|dataType|+-----------------------------+------------------------------+-----+--------+|2022-01-15T06:46:40.000+08:00|root.BHSFC.Q1.W002.WROT_HubTmp| 16.0| DOUBLE||2022-07-11T00:00:00.000+08:00| root.BHSFC.Q1.W003.speed| 1.0| FLOAT|+-----------------------------+------------------------------+-----+--------+Total line number = 2 -Hn
复制代码
2.2 使用 where 语句查询
2.2.1 时间过滤查询
我们可以查询某个时间段的数据,例如查询测试数据中 2022 年 1 月 12 日之前的数据,输入的 SQL 语句为:
select WROT_HubTmp from root.BHSFC.Q1.W002 where time <2022-01-12
复制代码
输出的结果如下(仅截取前 3 行数据):
IoTDB> select WROT_HubTmp from root.BHSFC.Q1.W002 where time <2022-01-12+-----------------------------+------------------------------+| Time|root.BHSFC.Q1.W002.WROT_HubTmp|+-----------------------------+------------------------------+|2022-01-11T21:51:40.000+08:00| 14.4||2022-01-11T21:51:54.000+08:00| 14.5||2022-01-11T21:52:01.000+08:00| 14.4|
复制代码
也可以查询某个时刻之前的数据,例如查询测试数据中 2022 年 1 月 22 日 5 点之前的数据,输入的 SQL 语句为:
select WROT_HubTmp from root.BHSFC.Q1.W002 where time <2022-01-12T05:00:00
复制代码
输出的结果如下(仅截取前 3 行数据):
IoTDB> select WROT_HubTmp from root.BHSFC.Q1.W002 where time <2022-01-12T05:00:00+-----------------------------+------------------------------+| Time|root.BHSFC.Q1.W002.WROT_HubTmp|+-----------------------------+------------------------------+|2022-01-11T21:51:40.000+08:00| 14.4||2022-01-11T21:51:54.000+08:00| 14.5||2022-01-11T21:52:01.000+08:00| 14.4|
复制代码
2.2.2 查询时间范围内的最新数据
我们可以查询时间序列的最新数据,如查询时间序列 root.BHSFC.Q1.W002.WROT_HubTmp 的最新数据,可使用如下 SQL 语句:
select last WROT_HubTmp from root.BHSFC.Q1.W002
复制代码
查询结果为:
IoTDB> select last WROT_HubTmp from root.BHSFC.Q1.W002+-----------------------------+------------------------------+-----+--------+| Time| timeseries|value|dataType|+-----------------------------+------------------------------+-----+--------+|2022-01-15T06:46:40.000+08:00|root.BHSFC.Q1.W002.WROT_HubTmp| 16.0| DOUBLE|+-----------------------------+------------------------------+-----+--------+Total line number = 1
复制代码
也可以查询某个时间前后的最新数据,如查询 2022 年 1 月 14 日零点之前的最新值,SQL 语句为:
select last WROT_HubTmp from root.BHSFC.Q1.W002 where time >= 2022-1-14T00:00:00
复制代码
2.2.3 值过滤查询
我们也可以查询值满足某些条件的数据,例如查询测试数据中值大于 20 的数据,输入的 SQL 语句为:
select WROT_HubTmp from root.BHSFC.Q1.W002 where WROT_HubTmp > 20
复制代码
输出的结果如下(仅截取前 3 行数据):
IoTDB> select WROT_HubTmp from root.BHSFC.Q1.W002 where WROT_HubTmp > 20+-----------------------------+------------------------------+| Time|root.BHSFC.Q1.W002.WROT_HubTmp|+-----------------------------+------------------------------+|2022-01-13T04:14:42.000+08:00| 20.1||2022-01-13T04:19:52.000+08:00| 20.1||2022-01-13T04:43:09.000+08:00| 20.1|
复制代码
或查询测试数据中值区间为[21,24]的数据,SQL 语句为:
select WROT_HubTmp from root.BHSFC.Q1.W002 where WROT_HubTmp >= 21 and WROT_HubTmp < 24
复制代码
输出的结果如下(仅截取前 3 行数据):
IoTDB> select WROT_HubTmp from root.BHSFC.Q1.W002 where WROT_HubTmp >= 21 and WROT_HubTmp < 24+-----------------------------+------------------------------+| Time|root.BHSFC.Q1.W002.WROT_HubTmp|+-----------------------------+------------------------------+|2022-01-12T15:03:50.000+08:00| 21.0||2022-01-12T15:39:21.000+08:00| 21.0||2022-01-12T15:39:36.000+08:00| 21.1|
复制代码
以上阐述的数据基本查询功能,执行命令后将直接返回值结果。然而对于求和、求平均数等希望对原始数据采取简单二次计算、继而返回计算结果的需求,如果先查出数值再计算会比较麻烦。
Apache IoTDB 为此类需求提供了内置的聚合函数,使用聚合函数一次查询即可完成求和、求平均数等类型的计算,即使用聚合查询,可以很快得到结果。下面将介绍聚合查询可实现的功能类型和使用的 SQL 命令。
3. 数据聚合查询
3.1 查询时间序列行数
3.1.1 查询单条时间序列行数
要查询导入的 CSV 测试数据一共有多少行,可输入 SQL 语句:
select count(WROT_HubTmp) from root.BHSFC.Q1.W002
复制代码
输出结果如下:
IoTDB> select count(WROT_HubTmp) from root.BHSFC.Q1.W002+-------------------------------------+|count(root.BHSFC.Q1.W002.WROT_HubTmp)|+-------------------------------------+| 13834|+-------------------------------------+Total line number = 1
复制代码
我们可以使用通配符简化查询语句,它的功能等价于上面的查询导入行数语句(*在路径中表示一层,**表示一层或多层):
select count(*) from root.**.W002
复制代码
我们同样可以使用通配符 * 查询写入的 SQL 语句一共有多少行,SQL 语句如下:
select count(*) from root.**.W003
复制代码
输出结果如下:
IoTDB> select count(*) from root.**.W003+-------------------------------+|count(root.BHSFC.Q1.W003.speed)|+-------------------------------+| 1|+-------------------------------+Total line number = 1
复制代码
3.1.2 查询多条时间序列行数
我们也可以一次查询多条时间序列,输入的 SQL 语句为(已使用通配符简化输入的字符):
select count(*) from root.**
复制代码
输出结果为写入的两条时间序列的名称和行数:
IoTDB> select count(*) from root.**+-------------------------------------+-------------------------------+|count(root.BHSFC.Q1.W002.WROT_HubTmp)|count(root.BHSFC.Q1.W003.speed)|+-------------------------------------+-------------------------------+| 13834| 1|+-------------------------------------+-------------------------------+Total line number = 1
复制代码
3.2 IoTDB 内置聚合函数功能
上面查询时间序列使用的 count 查询即是一个聚合函数,Apache IoTDB 内置的聚合函数有:
利用这些聚合函数,可以实现单层、分层聚合查询、分段聚合查询、空值填充等多种功能,下面就将详细介绍实现这些功能的过程。
3.2.1 单层聚合查询
例如我们要查询导入的测试数据中的最大值,输入的 SQL 语句为:
select MAX_VALUE(*) from root.BHSFC.Q1.W002
复制代码
输出结果为:
IoTDB> select MAX_VALUE(*) from root.BHSFC.Q1.W002+---------------------------------------+|EXTREME(root.BHSFC.Q1.W002.WROT_HubTmp)|+---------------------------------------+| 22.39999|+---------------------------------------+Total line number = 1
复制代码
如果需要求测试数据的平均值,输入的 SQL 语句为:
select AVG(*) from root.BHSFC.Q1.W002
复制代码
输出结果为:
IoTDB> select AVG(*) from root.BHSFC.Q1.W002+-----------------------------------+|AVG(root.BHSFC.Q1.W002.WROT_HubTmp)|+-----------------------------------+| 17.683083226110213|+-----------------------------------+Total line number = 1
复制代码
3.2.2 聚合查询+时间过滤
我们也可以对一段时间内的数据进行聚合查询,例如查询 1 月 13 日之后的数据总数:
select count(*) from root.BHSFC.Q1.W002 where time > 2022-01-13T00:00:00
复制代码
或查询 1 月 12 日至 1 月 13 日之间的数据总数:
select count(*) from root.BHSFC.Q1.W002 where time <= 2022-01-13T00:00:00 and time > 2022-01-12T00:00:00
复制代码
两次查询的输出结果为:
IoTDB> select count(*) from root.BHSFC.Q1.W002 where time > 2022-01-13T00:00:00+-------------------------------------+|count(root.BHSFC.Q1.W002.WROT_HubTmp)|+-------------------------------------+| 9985|+-------------------------------------+Total line number = 1It costs 0.007sIoTDB> select count(*) from root.BHSFC.Q1.W002 where time <= 2022-01-13T00:00:00 and time > 2022-01-12T00:00:00+-------------------------------------+|count(root.BHSFC.Q1.W002.WROT_HubTmp)|+-------------------------------------+| 3030|+-------------------------------------+Total line number = 1It costs 0.007s
复制代码
3.2.3 分层聚合查询
我们可以使用 GROUP BY LEVEL = INT 语句来对某一层级下的序列进行聚合查询。group by 子句可以将查询结果分组,并按照 group by 子句中指定的聚合函数表达式返回查询结果。
这里我们重温一下测试数据和我们创建的数据的层级:
根据上面的数据层级,如果我们查询 level 2 层级中的数据点个数,可以这样写 SQL 语句:
select count(*) from root.** group by level = 2
复制代码
输出结果如下:
IoTDB> select count(*) from root.** group by level = 2+--------------------+--------------------+|count(root.*.Q1.*.*)|count(root.*.wf01.*)|+--------------------+--------------------+| 13835| 2|+--------------------+--------------------+Total line number = 1
复制代码
分层聚合查询还可以用于对某一层级下同名的序列的查询。
例如我们现在有 root.BHSFC.Q1.W002.speed 序列,假如还有多条名为 speed 的序列,如
root.ln2.wf01.speed、root.ln2.wf02.speed、root.ln2.wf03.speed 等。
如果需要统计所有这些 speed 序列的数据点数,SQL 语句为:
select count(speed) from root.** group by level = 3
复制代码
由于这里没有实际创建上面这些序列,这里就不详细演示输出结果了,但这个操作非常方便,一句简单的 SQL 语句就能查询不同设备采集的同一物理量。
3.3 分段聚合查询
分段聚合是一种时序数据典型的查询方式,当我们按照一定的时间间隔进行聚合计算,比如计算每天的平均气温,就可以将气温的序列按天进行分段,然后计算每段的平均值。
我们通过 GROUP BY 子句指定按照时间区间分段聚合。例如查询测试数据中 1 月 14 号的平均风速,SQL 语句为:
select AVG(*) from root.BHSFC.Q1.W002 group by ([2022-1-14T00:00:00,2022-1-15T00:00:00),1d)
复制代码
括号左开右闭代表计算时包含 1 月 14 号零点的数据,不包含 1 月 15 号零点的数据。输出结果如下:
IoTDB> select AVG(*) from root.BHSFC.Q1.W002 group by ([2022-1-14T00:00:00,2022-1-15T00:00:00),1d)+-----------------------------+-----------------------------------+| Time|AVG(root.BHSFC.Q1.W002.WROT_HubTmp)|+-----------------------------+-----------------------------------+|2022-01-14T00:00:00.000+08:00| 17.880594558648433|+-----------------------------+-----------------------------------+Total line number = 1
复制代码
不仅单个时间序列可以进行时间区间分段聚合查询,多元时间序列也可以。例如我们可以查询 1 月 11 号到 1 月 15 号间每天前三小时内风速 speed 的数量和风速的最大值,SQL 语句如下:
select count(speed),max_value(WROT_HubTmp) from root.BHSFC.Q1.* group by ([2022-1-11T00:00:00,2022-1-15T00:00:00),3h,1d)
复制代码
输出结果为:
IoTDB> select count(speed),max_value(WROT_HubTmp) from root.BHSFC.Q1.* group by ([2022-1-11T00:00:00,2022-1-15T00:00:00),3h,1d)+-----------------------------+-------------------------------+-----------------------------------------+| Time|count(root.BHSFC.Q1.W003.speed)|max_value(root.BHSFC.Q1.W002.WROT_HubTmp)|+-----------------------------+-------------------------------+-----------------------------------------+|2022-01-11T00:00:00.000+08:00| 0| null||2022-01-12T00:00:00.000+08:00| 0| 18.2||2022-01-13T00:00:00.000+08:00| 0| 18.8||2022-01-14T00:00:00.000+08:00| 0| 18.39999|+-----------------------------+-------------------------------+-----------------------------------------+Total line number = 4
复制代码
因为我们此前只往 speed 写入了一个值,而这个值涉及的时间范围不包含在 1 月 11 日到 14 日内,所以这段时间内 speed 都没有值,统计的数据点数为 0 。而 1 月 11 日 0 点到 3 点的时间区间内,风速也没有值,所以下方这一栏显示为 null 。
max_value(root.BHSFC.Q1.W002.WROT_HubTmp)
复制代码
除上述典型的分段聚合查询场景外,分段聚合查询还有功能上的特例,这就是下面要说的降采样查询。
3.3.1 降采样查询
降采样查询是指使用比数据采集的时间频率更低的频率进行的一种查询方式,是分段聚合的一种特例。例如,数据采集的频率是一秒,如果想按照 1 分钟的频率对数据进行查询,则需要使用降采样查询。
在 Apache IoTDB 中可以通过 GROUP BY 子句指定聚合的时间间隔和滑动步长实现降采样查询,样式为
group by([startTime, endTime], time_window, sliding_step)
复制代码
其中 time_window 是聚合的时间窗口大小,sliding_step 是时间窗口的滑动步长,如下图所示。
下面我们看几个降采样查询的例子:
例句一:查询风机 2022 年 1 月 11 号到 15 号每天的最高风速:
select max_value (*) from root.BHSFC.Q1.W002 group by ([2022-1-11T00:00:00,2022-1-15T00:00:00),1d)
复制代码
例句二:查询风机 2022 年 1 月 11 号到 15 号每天上午的平均风速:
select avg(*) from root.BHSFC.Q1.W002 group by ([2022-1-11T00:00:00,2022-1-15T00:00:00),12h,1d)
复制代码
例句三:每隔半天统计 1 月 11 号之后 0 点到 6 点的平均风速:
select avg(*) from root.BHSFC.Q1. W002 group by ([2022-1-11T00:00:00,2022-1-15T00:00:00),6h,12h)
复制代码
上述例句的输出结果如下:
IoTDB> select max_value (*) from root.BHSFC.Q1.W002 group by ([2022-1-11T00:00:00,2022-1-15T00:00:00),1d)+-----------------------------+-----------------------------------------+| Time|max_value(root.BHSFC.Q1.W002.WROT_HubTmp)|+-----------------------------+-----------------------------------------+|2022-01-11T00:00:00.000+08:00| 18.7||2022-01-12T00:00:00.000+08:00| 21.1||2022-01-13T00:00:00.000+08:00| 20.2||2022-01-14T00:00:00.000+08:00| 22.39999|+-----------------------------+-----------------------------------------+Total line number = 4It costs 0.014sIoTDB> select avg(*) from root.BHSFC.Q1.W002 group by ([2022-1-11T00:00:00,2022-1-15T00:00:00),12h,1d)+-----------------------------+-----------------------------------+| Time|avg(root.BHSFC.Q1.W002.WROT_HubTmp)|+-----------------------------+-----------------------------------+|2022-01-11T00:00:00.000+08:00| 14.475876229508224||2022-01-12T00:00:00.000+08:00| 16.913640732526957||2022-01-13T00:00:00.000+08:00| 17.04472683120057||2022-01-14T00:00:00.000+08:00| 16.626656189856803|+-----------------------------+-----------------------------------+Total line number = 4It costs 0.010sIoTDB> select avg(*) from root.BHSFC.Q1. W002 group by ([2022-1-11T00:00:00,2022-1-15T00:00:00),6h,12h)+-----------------------------+-----------------------------------+| Time|avg(root.BHSFC.Q1.W002.WROT_HubTmp)|+-----------------------------+-----------------------------------+|2022-01-11T00:00:00.000+08:00| 14.263634545454543||2022-01-11T12:00:00.000+08:00| null||2022-01-12T00:00:00.000+08:00| 16.590661805896843||2022-01-12T12:00:00.000+08:00| 19.916664648437486||2022-01-13T00:00:00.000+08:00| 16.908698723897892||2022-01-13T12:00:00.000+08:00| 18.385164558333372||2022-01-14T00:00:00.000+08:00| 16.478693331408735||2022-01-14T12:00:00.000+08:00| 20.17386738693474|+-----------------------------+-----------------------------------+Total line number = 8
复制代码
3.3.2 分层+分段聚合查询
前面分层聚合中我们提到了对同名序列的查询,在分段聚合中我们也可以查询所有同名的序列。
例如如果不同存储组、不同设备的序列都命名为 WROT_HubTmp 如:root.BHSFC.Q2.W003.WROT_HubTmp、 root.ln2.wf01.WROT_HubTmp 等。
那么统计 2022 年 1 月 11 日至 15 日内所有设备下名叫 WROT_HubTmp 的序列每天的数据最大值,其 SQL 语句为:
select max_value(WROT_HubTmp) from root.** group by ((2022-1-11T00:00:00,2022-1-15T00:00:00],1d), level=3
复制代码
3.4 空值填充
在数据传输过程中,很容易产生空值,Apache IoTDB 的查询提供了前值、线性和特定值填充三种方法来方便快捷的填补空值。
3.4.1 前值填充
IoTDB 中可以使用前一个数据的值来填充此条数据的空值。
以测试数据为例,测试数据中此前在最新值查询中查到了最后一个数据的时间为 2022 年 1 月 15 日 06:46:40,这之后的数据就没有了。假如需要查询在这之后,如 2022 年 1 月 16 日 00:00:00 的数据,并使用前一个数据的值填充空值,则 SQL 语句为:
select WROT_HubTmp from root.BHSFC.Q1.W002 where time = 2022-01-16T00:00:00 fill(previous)
复制代码
返回结果为:
IoTDB> select WROT_HubTmp from root.BHSFC.Q1.W002 where time = 2022-01-15T23:00:00 fill(previous)+-----------------------------+------------------------------+| Time|root.BHSFC.Q1.W002.WROT_HubTmp|+-----------------------------+------------------------------+|2022-01-15T23:00:00.000+08:00| 16.0|+-----------------------------+------------------------------+Total line number = 1
复制代码
可以看到这个时间点的值与前一个时间点的值相同。
我们也可以指定前值的时间范围,例如最后一个数据的时间为 2022 年 1 月 15 日 06:46:40,我们想要查询 2022 年 1 月 15 日 06:47:00 的数据,且想要填充数值位于空值前一分钟内,则 SQL 语句为:
select WROT_HubTmp from root.BHSFC.Q1.W002 where time = 2022-01-15T06:47:00 fill(previous,1m)
复制代码
返回结果为:
IoTDB> select WROT_HubTmp from root.BHSFC.Q1.W002 where time = 2022-01-15T06:47:00 fill(previous,1m)+-----------------------------+------------------------------+| Time|root.BHSFC.Q1.W002.WROT_HubTmp|+-----------------------------+------------------------------+|2022-01-15T06:47:00.000+08:00| 16.0|+-----------------------------+------------------------------+Total line number = 1
复制代码
如果不指定,则默认时间范围为无穷大,至找到前值为止。如果前一个时间点为空,那么填充指令返回的结果也为空。
例如我们的前值范围限定在 48 分的前一分钟,那个时间点没有数值,则返回 null ,如下所示:
IoTDB> select WROT_HubTmp from root.BHSFC.Q1.W002 where time = 2022-01-15T06:48:00 fill(previous,1m)+-----------------------------+------------------------------+| Time|root.BHSFC.Q1.W002.WROT_HubTmp|+-----------------------------+------------------------------+|2022-01-15T06:48:00.000+08:00| null|+-----------------------------+------------------------------+Total line number = 1
复制代码
3.4.2 线性填充
在降采样查询中我们有这样一个例句,每隔半天统计 1 月 11 号至 1 月 15 日 0 点到 6 点的平均风速:
select avg(*) from root.BHSFC.Q1. W002 group by ([2022-1-11T00:00:00,2022-1-15T00:00:00),6h,12h)
复制代码
返回结果为:
IoTDB> select avg(*) from root.BHSFC.Q1. W002 group by ([2022-1-11T00:00:00,2022-1-15T00:00:00),6h,12h)+-----------------------------+-----------------------------------+| Time|avg(root.BHSFC.Q1.W002.WROT_HubTmp)|+-----------------------------+-----------------------------------+|2022-01-11T00:00:00.000+08:00| 14.263634545454543||2022-01-11T12:00:00.000+08:00| null||2022-01-12T00:00:00.000+08:00| 16.590661805896843||2022-01-12T12:00:00.000+08:00| 19.916664648437486||2022-01-13T00:00:00.000+08:00| 16.908698723897892||2022-01-13T12:00:00.000+08:00| 18.385164558333372||2022-01-14T00:00:00.000+08:00| 16.478693331408735||2022-01-14T12:00:00.000+08:00| 20.17386738693474|+-----------------------------+-----------------------------------+
复制代码
可以看到第二行数据返回了 null ,是空值,因为那段时间内没有数据。我们可以用线性填充把这个值填上,SQL 语句为:
select avg(*) from root.BHSFC.Q1. W002 group by ([2022-1-11T00:00:00,2022-1-15T00:00:00),6h,12h) fill (linear)
复制代码
返回结果为:
IoTDB> select avg(*) from root.BHSFC.Q1. W002 group by ([2022-1-11T00:00:00,2022-1-15T00:00:00),6h,12h) fill (linear)+-----------------------------+-----------------------------------+| Time|avg(root.BHSFC.Q1.W002.WROT_HubTmp)|+-----------------------------+-----------------------------------+|2022-01-11T00:00:00.000+08:00| 14.263634545454543||2022-01-11T12:00:00.000+08:00| 15.427148175675693||2022-01-12T00:00:00.000+08:00| 16.590661805896843||2022-01-12T12:00:00.000+08:00| 19.916664648437486||2022-01-13T00:00:00.000+08:00| 16.908698723897892||2022-01-13T12:00:00.000+08:00| 18.385164558333372||2022-01-14T00:00:00.000+08:00| 16.478693331408735||2022-01-14T12:00:00.000+08:00| 20.17386738693474|+-----------------------------+-----------------------------------+
复制代码
可以看到空值已经被填充了,这个值是前值 14.263634545454543 和后值 16.590661805896843 的线性插值。
3.4.3 特定值填充
我们也可以用特定的常值进行填充,例如 16 号零点的数据都为空,希望显示为 15 ,则 SQL 语句为:
select WROT_HubTmp from root.BHSFC.Q1.W002 where time = 2022-01-16T00:00:00 fill(15)
复制代码
返回结果为:
IoTDB> select WROT_HubTmp from root.BHSFC.Q1.W002 where time = 2022-01-16T00:00:00 fill(15)+-----------------------------+------------------------------+| Time|root.BHSFC.Q1.W002.WROT_HubTmp|+-----------------------------+------------------------------+|2022-01-16T00:00:00.000+08:00| 15.0|+-----------------------------+------------------------------+
复制代码
4. 结语
至此我们了解了 Apache IoTDB 可实现的数据导入和查询功能,和具体如何实现这些功能的 SQL 例句。接下来的最后一篇教程将介绍 IoTDB 可实现的其他功能,包括数据的删除、导出和元数据操作。
评论