| <!-- |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| |
| --> |
| |
| ## 查询补空值 |
| |
| 当对序列进行分段聚合时,某一段时间可能不存在数据,则此段数据的聚合结果为空,但这种空值不利于进行数据可视化展示和分析,需要对空值进行填补。 |
| |
| 查询补空值允许用户按照特定的方法对查询结果填充空值,如取前一个不为空的值,或线性插值。补空值之后的查询结果能更好地反映数据分布,有利于用户进行数据分析。 |
| |
| 在 IoTDB 中,用户可以使用 FILL 子句指定某一时间点或一时间窗口数据缺失的情况下的填充模式。如果查询点空,则填充功能将不起作用。 |
| |
| ### 填充方法 |
| |
| IoTDB 目前支持 `previous` , `linear`, `value` 三种空值填充方式,数据类型和支持的填充方法如下表所示: |
| |
| | 数据类型 | 支持的填充方法 | |
| | :------- | :---------------------- | |
| | boolean | previous, value | |
| | int32 | previous, linear, value | |
| | int64 | previous, linear, value | |
| | float | previous, linear, value | |
| | double | previous, linear, value | |
| | text | previous, value | |
| |
| > 注意:在 Fill 语句中只能指定一种填充方法。空值填充兼容 0.12 版本及以前的语法(即 fill((<data_type>[<fill_method>(, <before_range>, <after_range>)?])+)),但老的语法也不能同时指定多种填充方式。 |
| |
| ### 单点补空值 |
| |
| 当某一特定时间戳的数据为空时,可以使用单值填充对空值进行填充,详细说明如下: |
| |
| #### Previous 填充 |
| |
| 当查询的时间戳下数据为空时,将使用前一个时间戳的值来填充空白。 语法定义如下: |
| |
| ```sql |
| select <path> from <prefixPath> where time = <T> fill(previous(, <before_range>)?) |
| ``` |
| |
| 下表给出了所有参数的详细说明: |
| |
| | 参数名称(不区分大小写) | 解释 | |
| | :----------------------- | :----------------------------------------------------------- | |
| | path, prefixPath | 查询路径; 必填项 | |
| | T | 查询时间戳(只能指定一个); 必填项 | |
| | before\_range | 表示前一种方法的有效时间范围。 当 [T-before\_range,T] 范围内的值存在时,前一种方法将起作用。 如果未指定 before_range,则 before_range 会使用默认值 default_fill_interval; -1 表示无穷大; 可选字段 | |
| |
| 在这里,我们举一个使用 Previous 方法填充空值的示例。 SQL 语句如下: |
| |
| ```sql |
| select temperature from root.sgcc.wf03.wt01 where time = 2017-11-01T16:37:50.000 fill(previous, 1m) |
| ``` |
| |
| 含义: |
| |
| 由于时间根目录 root.sgcc.wf03.wt01.temperature 在 2017-11-01T16:37:50.000 为空,因此系统使用以前的时间戳 2017-11-01T16:37:00.000(且时间戳位于 [2017-11-01T16:36:50.000, 2017-11-01T16:37:50.000] 范围)进行填充和显示。 |
| |
| 在 [样例数据](https://github.com/thulab/iotdb/files/4438687/OtherMaterial-Sample.Data.txt) 中, 该语句的执行结果如下所示: |
| |
| ``` |
| +-----------------------------+-------------------------------+ |
| | Time|root.sgcc.wf03.wt01.temperature| |
| +-----------------------------+-------------------------------+ |
| |2017-11-01T16:37:50.000+08:00| 21.93| |
| +-----------------------------+-------------------------------+ |
| Total line number = 1 |
| It costs 0.016s |
| ``` |
| |
| 值得注意的是,如果在指定的有效时间范围内没有值,系统将不会填充空值,如下所示: |
| |
| ``` |
| IoTDB> select temperature from root.sgcc.wf03.wt01 where time = 2017-11-01T16:37:50.000 fill(previous, 1s) |
| +-----------------------------+-------------------------------+ |
| | Time|root.sgcc.wf03.wt01.temperature| |
| +-----------------------------+-------------------------------+ |
| |2017-11-01T16:37:50.000+08:00| null| |
| +-----------------------------+-------------------------------+ |
| Total line number = 1 |
| It costs 0.004s |
| ``` |
| |
| #### Linear 填充 |
| |
| 当查询的时间戳下数据为空时,将使用前一个和下一个时间戳的值来填充空白。 语法定义如下: |
| |
| ```sql |
| select <path> from <prefixPath> where time = <T> fill(linear(, <before_range>, <after_range>)?) |
| ``` |
| |
| 下表给出了所有参数的详细说明: |
| |
| | 参数名称(不区分大小写) | 解释 | |
| | :-------------------------- | :----------------------------------------------------------- | |
| | path, prefixPath | 查询路径; 必填项 | |
| | T | 查询时间戳(只能指定一个); 必填项 | |
| | before\_range, after\_range | 表示线性方法的有效时间范围。 当 [T - before\_range,T + after\_range] 范围内的值存在时,前一种方法将起作用。 如果未明确指定 before\_range 和 after\_range,则使用 default\_fill\_interval。 -1 表示无穷大; 可选字段 | |
| |
| 需要注意的是一旦时间序列在查询时间戳 T 时刻存在有效值,线性填充就会使用这个值作为结果返回。 |
| 除此之外,如果在 [T - before_range, T] 或 [T, T + after_range] 两个范围中任意一个范围内不存在有效填充值,则线性填充返回 null 值。 |
| |
| 在这里,我们举一个使用线性方法填充空值的示例。 SQL 语句如下: |
| |
| ```sql |
| select temperature from root.sgcc.wf03.wt01 where time = 2017-11-01T16:37:50.000 fill(linear, 1m, 1m) |
| ``` |
| |
| 含义: |
| |
| 由于时间根目录 root.sgcc.wf03.wt01.temperature 在 2017-11-01T16:37:50.000 为空,因此系统使用以前的时间戳 2017-11-01T16:37:00.000(且时间戳位于 [2017-11-01T16:36:50.000,2017-11-01T16:37:50.000) 时间范围)及其值 21.927326,下一个时间戳记 2017-11-01T16:38:00.000(且时间戳记位于 (2017-11-01T16:37:50.000, 2017-11-01T16:38:50.000) 时间范围)及其值 25.311783 以执行线性拟合计算: |
| |
| 21.927326 +(25.311783-21.927326)/ 60s * 50s = 24.747707 |
| |
| 在 [样例数据](https://github.com/thulab/iotdb/files/4438687/OtherMaterial-Sample.Data.txt) 中, 该语句的执行结果如下所示: |
| |
| ``` |
| +-----------------------------+-------------------------------+ |
| | Time|root.sgcc.wf03.wt01.temperature| |
| +-----------------------------+-------------------------------+ |
| |2017-11-01T16:37:50.000+08:00| 24.747707| |
| +-----------------------------+-------------------------------+ |
| Total line number = 1 |
| It costs 0.017s |
| ``` |
| |
| #### Value 填充 |
| |
| 当查询的时间戳下数据为空时,将使用给定的值来填充空白。语法定义如下: |
| |
| ```sql |
| select <path> from <prefixPath> where time = <T> fill(constant) |
| ``` |
| |
| 下表给出了所有参数的详细说明: |
| |
| | 参数名称(不区分大小写) | 解释 | |
| | :----------------------- | :---------------------------------- | |
| | path, prefixPath | 查询路径; 必填项 | |
| | T | 查询时间戳(只能指定一个); 必填项 | |
| | constant | 给定的填充值;必填项 | |
| |
| 需要注意的是一旦时间序列在查询时间戳T时刻存在有效值,特定值填充就会使用这个值作为结果返回。 |
| |
| |
| 在这里,我们举一个使用特定值方法填充空值的示例。 SQL语句如下: |
| |
| ```sql |
| select temperature from root.sgcc.wf03.wt01 where time = 2017-11-01T16:37:50.000 fill(2.0) |
| ``` |
| |
| 含义: |
| |
| 由于时间序列 root.sgcc.wf03.wt01.temperature 在 2017-11-01T16:37:50.000 为空,因此使用给定的值 2.0 进行填充: |
| |
| 在 [样例数据](https://github.com/thulab/iotdb/files/4438687/OtherMaterial-Sample.Data.txt) 中, 该语句的执行结果如下所示: |
| |
| ``` |
| +-----------------------------+-------------------------------+ |
| | Time|root.sgcc.wf03.wt01.temperature| |
| +-----------------------------+-------------------------------+ |
| |2017-11-01T16:37:50.000+08:00| 2.0 | |
| +-----------------------------+-------------------------------+ |
| Total line number = 1 |
| It costs 0.007s |
| ``` |
| |
| 在使用 VALUE 方法填充时需要注意,如果查询结果的数据类型与输入常量值不同,IoTDB 将不进行填充 |
| |
| 示例: |
| ```sql |
| select temperature from root.sgcc.wf03.wt01 where time = 2017-11-01T16:37:50.000 fill('test') |
| ``` |
| |
| 结果: |
| ``` |
| +-----------------------------+-------------------------------+ |
| | Time|root.sgcc.wf03.wt01.temperature| |
| +-----------------------------+-------------------------------+ |
| |2017-11-01T16:37:50.000+08:00| null | |
| +-----------------------------+-------------------------------+ |
| Total line number = 1 |
| It costs 0.007s |
| ``` |
| |
| ### 降采样补空值 |
| |
| IoTDB 支持对原降采样结果进行空值填充,`previous`、`linear`、`value` 填充方式均可作用于查询语句中的任一聚合算子,但一条查询语句只能使用一种空值填充方式。此外,使用时需要注意以下两点: |
| |
| - 在任何情形下都不会填充 `count` 的聚合结果,因为对于不存在任数据的查询区间,`count` 的结果为 0。 |
| - 分类处理 sum 的聚合结果:若某个查询区间不存在任何数据,sum 的聚合结果为 null,将被 GroupByFill 填充;若某个查询区间内 sum 的聚合结果恰好为 0,那么 GroupByFill 不会填充这个值。 |
| |
| 降采样补空值查询语法同单点补空值查询语法相似,下面列出简单的示例和使用细节: |
| |
| #### PREVIOUS 和 PREVIOUSUNTILLAST 的区别 |
| |
| * PREVIOUS:只要空值前边有值,就会用其填充空值。 |
| * PREVIOUSUNTILLAST:不会填充此序列最新点后的空值。 |
| |
| 首先检查一下 root.ln.wf01.wt01.temperature 在时间 2017-11-07T23:49:00 以后的值: |
| |
| ``` |
| IoTDB> SELECT temperature FROM root.ln.wf01.wt01 where time >= 2017-11-07T23:49:00 |
| +-----------------------------+-----------------------------+ |
| | Time|root.ln.wf01.wt01.temperature| |
| +-----------------------------+-----------------------------+ |
| |2017-11-07T23:49:00.000+08:00| 23.7| |
| |2017-11-07T23:51:00.000+08:00| 22.24| |
| |2017-11-07T23:53:00.000+08:00| 24.58| |
| |2017-11-07T23:54:00.000+08:00| 22.52| |
| |2017-11-07T23:57:00.000+08:00| 24.39| |
| |2017-11-08T00:00:00.000+08:00| 21.07| |
| +-----------------------------+-----------------------------+ |
| Total line number = 6 |
| It costs 0.010s |
| ``` |
| |
| root.ln.wf01.wt01.temperature 最早时间和值是 2017-11-07T23:49:00 和 23.7;最后时间和值是 2017-11-08T00:00:00 和 21.07 |
| |
| SQL 示例: |
| |
| ```sql |
| SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (PREVIOUSUNTILLAST); |
| SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (PREVIOUS); |
| ``` |
| |
| 结果: |
| |
| ``` |
| IoTDB> SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (PREVIOUSUNTILLAST); |
| +-----------------------------+-----------------------------------------+ |
| | Time|last_value(root.ln.wf01.wt01.temperature)| |
| +-----------------------------+-----------------------------------------+ |
| |2017-11-07T23:50:00.000+08:00| null| |
| |2017-11-07T23:51:00.000+08:00| 22.24| |
| |2017-11-07T23:52:00.000+08:00| 22.24| |
| |2017-11-07T23:53:00.000+08:00| 24.58| |
| |2017-11-07T23:54:00.000+08:00| 22.52| |
| |2017-11-07T23:55:00.000+08:00| 22.52| |
| |2017-11-07T23:56:00.000+08:00| 22.52| |
| |2017-11-07T23:57:00.000+08:00| 24.39| |
| |2017-11-07T23:58:00.000+08:00| null| |
| +-----------------------------+-----------------------------------------+ |
| Total line number = 9 |
| It costs 0.007s |
| |
| IoTDB> SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (PREVIOUS); |
| +-----------------------------+-----------------------------------------+ |
| | Time|last_value(root.ln.wf01.wt01.temperature)| |
| +-----------------------------+-----------------------------------------+ |
| |2017-11-07T23:50:00.000+08:00| null| |
| |2017-11-07T23:51:00.000+08:00| 22.24| |
| |2017-11-07T23:52:00.000+08:00| 22.24| |
| |2017-11-07T23:53:00.000+08:00| 24.58| |
| |2017-11-07T23:54:00.000+08:00| 22.52| |
| |2017-11-07T23:55:00.000+08:00| 22.52| |
| |2017-11-07T23:56:00.000+08:00| 22.52| |
| |2017-11-07T23:57:00.000+08:00| 24.39| |
| |2017-11-07T23:58:00.000+08:00| 24.39| |
| +-----------------------------+-----------------------------------------+ |
| Total line number = 9 |
| It costs 0.006s |
| ``` |
| |
| 解释: |
| |
| 使用 PREVIOUSUNTILLAST 将不会填充 2017-11-07T23:57:00 以后的值。 |
| |
| #### 第一个值与最后一个值的填充 |
| |
| IoTDB 的空值填充方式可以分为 PreviousFill, LinearFill, ValueFill 三大类。其中,PreviousFill 需要知道空值前的第一个非空数据,LinearFill 需要知道空值前后的第一个非空数据才能进行填充。假使某条查询语句返回的结果中第一个或最后一个值为空,就可能导致结果集在首尾存在一段连续的空值,不满足 GroupByFill 的业务期望。 |
| |
| 在上例中,第一个时间区间 [2017-11-07T23:50:00, 2017-11-07T23:51:00) 内没有任何数据,上一个有数据的时间区间是 [2017-11-01T23:49:00, 2017-11-07T23:50:00),可以通过设置 PREVIOUS 填充向前查询参数 beforeRange 来填充第一个区间的数据,示例如下: |
| |
| ```sql |
| SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (PREVIOUS, 1m); |
| ``` |
| |
| 结果: |
| |
| ``` |
| IoTDB> SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (PREVIOUS, 1m); |
| +-----------------------------+-----------------------------------------+ |
| | Time|last_value(root.ln.wf01.wt01.temperature)| |
| +-----------------------------+-----------------------------------------+ |
| |2017-11-07T23:50:00.000+08:00| 23.7| |
| |2017-11-07T23:51:00.000+08:00| 22.24| |
| |2017-11-07T23:52:00.000+08:00| 22.24| |
| |2017-11-07T23:53:00.000+08:00| 24.58| |
| |2017-11-07T23:54:00.000+08:00| 22.52| |
| |2017-11-07T23:55:00.000+08:00| 22.52| |
| |2017-11-07T23:56:00.000+08:00| null| |
| |2017-11-07T23:57:00.000+08:00| 24.39| |
| |2017-11-07T23:58:00.000+08:00| 24.39| |
| +-----------------------------+-----------------------------------------+ |
| Total line number = 9 |
| It costs 0.005s |
| ``` |
| |
| 解释: |
| |
| 为了不与原有语义冲突,当不设置 before_range, after_range 参数时,GroupByFill 的空值填充取空值的前一个/后一个非空值完成;当设置 before_range, after_range 参数时,设空值所在记录的时间戳为 t,GroupByFill 取 [t-before_range, t+after_range) 内的前一个/后一个非空值完成填充。 |
| |
| 因为时间区间 [2017-11-07T23:55:00, 2017-11-07T23:57:00) 内均没有数据,所以本例虽然通过设置 before_range 填充了 [2017-11-07T23:50:00, 2017-11-07T23:51:00) 的数据,但由于 before_range 较小,[2017-11-07T23:56:00, 2017-11-07T23:57:00) 的数据无法填充。 |
| |
| before_range, after_range 参数也可辅助 LINEAR 方式进行填充,示例如下: |
| |
| ```sql |
| SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (LINEAR, 5m, 5m); |
| ``` |
| |
| 结果: |
| |
| ``` |
| IoTDB> SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (LINEAR, 5m, 5m); |
| +-----------------------------+-----------------------------------------+ |
| | Time|last_value(root.ln.wf01.wt01.temperature)| |
| +-----------------------------+-----------------------------------------+ |
| |2017-11-07T23:50:00.000+08:00| 22.970001| |
| |2017-11-07T23:51:00.000+08:00| 22.24| |
| |2017-11-07T23:52:00.000+08:00| 23.41| |
| |2017-11-07T23:53:00.000+08:00| 24.58| |
| |2017-11-07T23:54:00.000+08:00| 22.52| |
| |2017-11-07T23:55:00.000+08:00| 23.143333| |
| |2017-11-07T23:56:00.000+08:00| 23.766666| |
| |2017-11-07T23:57:00.000+08:00| 24.39| |
| |2017-11-07T23:58:00.000+08:00| 23.283333| |
| +-----------------------------+-----------------------------------------+ |
| Total line number = 9 |
| It costs 0.008s |
| ``` |
| |
| > 注意:设原始降采样查询区间为 [start_time, end_time),在指定 before_range, after_range 参数后,降采样查询结果不变,但查询区间将转变为 [start_time - before_range, end_time + after_range)。因此这两个参数设置较大时会影响效率,使用时需注意。 |
| |
| #### Value 填充 |
| |
| 值填充方式会将输入的常量值解析为字符串,填充时尝试将字符串常量转换为对应类型的数据,若转换成功则进行填充,否则就不填充。举例如下: |
| |
| ```sql |
| SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (20.0) |
| SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL ('temperature') |
| ``` |
| |
| 结果: |
| |
| ``` |
| IoTDB> SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (20.0); |
| +-----------------------------+-----------------------------------------+ |
| | Time|last_value(root.ln.wf01.wt01.temperature)| |
| +-----------------------------+-----------------------------------------+ |
| |2017-11-07T23:50:00.000+08:00| 20.0| |
| |2017-11-07T23:51:00.000+08:00| 22.24| |
| |2017-11-07T23:52:00.000+08:00| 20.0| |
| |2017-11-07T23:53:00.000+08:00| 24.58| |
| |2017-11-07T23:54:00.000+08:00| 22.52| |
| |2017-11-07T23:55:00.000+08:00| 20.0| |
| |2017-11-07T23:56:00.000+08:00| 20.0| |
| |2017-11-07T23:57:00.000+08:00| 24.39| |
| |2017-11-07T23:58:00.000+08:00| 20.0| |
| +-----------------------------+-----------------------------------------+ |
| Total line number = 9 |
| It costs 0.007s |
| |
| IoTDB> SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL ('temperature'); |
| +-----------------------------+-----------------------------------------+ |
| | Time|last_value(root.ln.wf01.wt01.temperature)| |
| +-----------------------------+-----------------------------------------+ |
| |2017-11-07T23:50:00.000+08:00| null| |
| |2017-11-07T23:51:00.000+08:00| 22.24| |
| |2017-11-07T23:52:00.000+08:00| null| |
| |2017-11-07T23:53:00.000+08:00| 24.58| |
| |2017-11-07T23:54:00.000+08:00| 22.52| |
| |2017-11-07T23:55:00.000+08:00| null| |
| |2017-11-07T23:56:00.000+08:00| null| |
| |2017-11-07T23:57:00.000+08:00| 24.39| |
| |2017-11-07T23:58:00.000+08:00| null| |
| +-----------------------------+-----------------------------------------+ |
| Total line number = 9 |
| It costs 0.005s |
| ``` |