|
| 1 | +# 插值 |
| 2 | + |
| 3 | +对时序数据进行分析或观测,通常需要对数据进行降采样,然后针对每个采样窗口中的数据应用聚合函数。 |
| 4 | +由于原始数据缺失或稀疏,或者采样窗口选取过大,可能导致某些采样窗口中没有数据。这不利于分析或观测时序数据。 |
| 5 | + |
| 6 | +为此,Datalayers 提供了插值功能,支持补全查询时间范围内缺失的采样窗口,并使用给定的插值函数对缺失的值进行填充。 |
| 7 | +补全的功能由 `date_bin_gapfill` 函数提供,插值的功能由插值函数提供。 |
| 8 | + |
| 9 | +## 基础语法 |
| 10 | + |
| 11 | +为了实现插值,您需要: |
| 12 | + |
| 13 | +1. 对时间戳列应用 `date_bin_gapfill` 函数,并将其作为分组列之一。 |
| 14 | + - 函数签名:`date_bin_gapfill(<interval>, <timestamp_column>[, <origin>])`。 |
| 15 | + - `interval`:采样窗口大小,可以为 `INTERVAL` 类型的字面值,或者结果为 `INTERVAL` 类型的表达式。 |
| 16 | + - `timestamp_column`:时间戳列,列约束中必须包含 NOT NULL。 |
| 17 | + - `origin`:可选参数,指定根据哪个时间戳以对齐时间窗口。 |
| 18 | +2. 对聚合列应用插值函数。 |
| 19 | + - 线性插值:`fill_linear(<aggregate_col>)`。 |
| 20 | + - 使用该列前一个非空值填充:`fill_prev(<aggregate_col>)`。 |
| 21 | + - 使用给定值填充:`fill_value(<aggregate_col>, <value>)`。 |
| 22 | +3. 使用 WHERE 从句给定查询的时间范围。 |
| 23 | + - 时间范围必须为有限范围,即有限的起始时间戳与有限的结束时间戳。 |
| 24 | + |
| 25 | +语法示例: |
| 26 | + |
| 27 | +``` sql |
| 28 | +SELECT |
| 29 | + date_bin_gapfill(interval 1 hour, time) as window, |
| 30 | + fill_linear(avg(usage_user)), |
| 31 | + fill_prev(avg(usage_system)), |
| 32 | + fill_value(avg(usage_idle), 25.0) |
| 33 | +FROM cpu |
| 34 | +WHERE time >= '2024-01-16T08:00:00' AND time <= '2024-01-17T12:00:00' |
| 35 | +GROUP BY window |
| 36 | +``` |
| 37 | + |
| 38 | +## date_bin_gapfill 函数 |
| 39 | + |
| 40 | +我们提供了一个 [`date_bin`](./date.md) 函数用来将数据划分到采样窗口。在此基础上,`date_bin_gapfill` 函数还会额外补全缺失的采样窗口。让我们用一个简单的例子来解释。 |
| 41 | + |
| 42 | +给定原始时间序列: |
| 43 | + |
| 44 | +``` text |
| 45 | ++---------------------------+ |
| 46 | +| 2024-01-16T10:40:00+08:00 | |
| 47 | +| 2024-01-16T11:40:00+08:00 | |
| 48 | +| 2024-01-16T12:40:00+08:00 | |
| 49 | ++---------------------------+ |
| 50 | +``` |
| 51 | + |
| 52 | +将采样窗口大小设定为 30 分钟,应用 `date_bin` 函数后,每个时间戳被划分到它所属的采样窗口。 |
| 53 | +例如, `2024-01-16T10:40:00+08:00` 这条记录被划分到起始时间戳为 `2024-01-16T10:30:00+08:00` 的采样窗口。 |
| 54 | + |
| 55 | +``` text |
| 56 | ++---------------------------+ |
| 57 | +| 2024-01-16T10:30:00+08:00 | |
| 58 | +| 2024-01-16T11:30:00+08:00 | |
| 59 | +| 2024-01-16T12:30:00+08:00 | |
| 60 | ++---------------------------+ |
| 61 | +``` |
| 62 | + |
| 63 | +使用同样的窗口大小,应用 `date_bin_gapfill` 函数后,缺失的采样窗口得到补全。 |
| 64 | +例如,在起始时间为 `2024-01-16T10:30:00+08:00` 的窗口和起始时间为 `2024-01-16T11:30:00+08:00` 的窗口之间存在一个缺失的、起始时间为 `2024-01-16T11:00:00+08:00` 的采样窗口。这些缺失的采样窗口会被补全。 |
| 65 | + |
| 66 | +``` text |
| 67 | ++---------------------------+ |
| 68 | +| 2024-01-16T10:30:00+08:00 | |
| 69 | +| 2024-01-16T11:00:00+08:00 | |
| 70 | +| 2024-01-16T11:30:00+08:00 | |
| 71 | +| 2024-01-16T12:00:00+08:00 | |
| 72 | +| 2024-01-16T12:30:00+08:00 | |
| 73 | ++---------------------------+ |
| 74 | +``` |
| 75 | + |
| 76 | +与 `date_bin` 函数类似,`date_bin_gapfill` 函数也支持一个可选的 `origin` 参数。这个参数控制采样窗口根据哪个时间戳进行对齐。 |
| 77 | +`origin` 默认为 UTC 时区的 `1970-01-01T00:00:00` 时间。 |
| 78 | +对于我们的例子,如果将 `origin` 设置为 `1970-01-01T00:05:00`,则应用 `date_bin_gapfill` 后的结果为: |
| 79 | + |
| 80 | +``` text |
| 81 | ++---------------------------+ |
| 82 | +| 2024-01-16T10:35:00+08:00 | |
| 83 | +| 2024-01-16T11:05:00+08:00 | |
| 84 | +| 2024-01-16T11:35:00+08:00 | |
| 85 | +| 2024-01-16T12:05:00+08:00 | |
| 86 | +| 2024-01-16T12:35:00+08:00 | |
| 87 | ++---------------------------+ |
| 88 | +``` |
| 89 | + |
| 90 | +## 插值函数 |
| 91 | + |
| 92 | +插值函数用来对每个缺失的采样窗口中的聚合列进行填充。我们目前支持三种填充策略,分别对应三个插值函数: |
| 93 | + |
| 94 | +- `fill_linear`:对于一个缺失行,使用该列前一个非空行以及后一个非空行的线性插值进行填充。如果前或后没有非空行,则不填充。 |
| 95 | +- `fill_prev`:对于一个缺失行,使用该列前一个非空行的值进行填充。如果前面没有非空行,则不填充。 |
| 96 | +- `fill_value`:对于一个缺失行,使用给定的值进行填充。 |
| 97 | + |
| 98 | +特别注意,如果 SQL 语句中包含时间戳列之外的分组列,那么插值会针对每个分组单独执行。这是考虑到不同分组的数据可能没有显著的关联,如果允许跨分组插值,可能得到异常点(Outlier)。 |
| 99 | + |
| 100 | +## 其他注意事项 |
| 101 | + |
| 102 | +- `date_bin_gapfill` 只能作为投影列,且必须作为分组列。 |
| 103 | +- 插值函数只能作为投影列,不能出现在其他从句中。 |
| 104 | +- `date_bin_gapfill` 和插值函数只能作为最外层的表达式。例如 `count(date_bin_gapfill(..))`、`max(fill_prev(avg(usage_user)))` 都是不允许的。 |
| 105 | +- `date_bin_gapfill` 在一个 SQL 中最多只能出现一次。 |
| 106 | +- `date_bin_gapfill` 的 `interval` 和 `origin` 参数可以为子面量,也可以为表达式,只要表达式的类型符合要求。 |
| 107 | +- 插值函数必须和 `date_bin_gapfill` 函数联合使用,但是 `date_bin_gapfill` 函数可以单独使用。 |
| 108 | +- 每个聚合列最多只能应用一个插值函数。例如 `SELECT date_bin_gapfill(...), fill_linear(avg(usage_user)), fill_prev(avg(usage_user)) FROM CPU ...` 是不允许的。 |
| 109 | +- 插值后的结果总会使用分组列进行排序。 |
| 110 | +- 插值后的数据的时间范围为 `WHERE` 从句中指定的时间范围与每个分组内数据的时间范围的较大者。 |
| 111 | +- `fill_linear`、`fill_prev`、`fill_value` 实际上是函数的别名。它们的标准名称分别为 `interpolate`、`locf`、`value`。在 SQL 语句中,可以随意使用标准名称或者别名。但是在打印的结果集中,我们总是使用标准名称作为列名。 |
| 112 | + |
| 113 | +## 示例 |
| 114 | + |
| 115 | +给定 `cpu` 表的原始数据如下: |
| 116 | + |
| 117 | +``` text |
| 118 | ++---------------------------+------------+------------+--------------+------------+ |
| 119 | +| time | region | usage_user | usage_system | usage_idle | |
| 120 | ++---------------------------+------------+------------+--------------+------------+ |
| 121 | +| 2024-01-16T10:40:00+08:00 | us-west | 55.0 | 25.0 | 20.0 | |
| 122 | +| 2024-01-16T11:40:00+08:00 | us-east | 56.5 | 24.0 | 19.5 | |
| 123 | +| 2024-01-16T12:40:00+08:00 | us-central | 54.0 | 26.0 | 20.0 | |
| 124 | +| 2024-01-16T15:40:00+08:00 | eu-west | 58.0 | 22.0 | 20.0 | |
| 125 | +| 2024-01-16T18:40:00+08:00 | ap-south | 55.5 | 25.0 | 19.5 | |
| 126 | +| 2024-01-16T19:40:00+08:00 | eu-east | 59.0 | 21.5 | 19.5 | |
| 127 | +| 2024-01-16T22:40:00+08:00 | us-west | 57.0 | 23.5 | 19.5 | |
| 128 | +| 2024-01-17T04:40:00+08:00 | us-east | 60.0 | 20.5 | 19.5 | |
| 129 | +| 2024-01-17T05:40:00+08:00 | us-central | 58.5 | 22.5 | 19.0 | |
| 130 | +| 2024-01-17T08:40:00+08:00 | eu-west | 61.0 | 19.5 | 19.5 | |
| 131 | +| 2024-01-17T11:40:00+08:00 | ap-south | 59.5 | 20.0 | 20.5 | |
| 132 | +| 2024-01-17T15:20:00+08:00 | eu-east | 60.5 | 19.0 | 20.5 | |
| 133 | +| 2024-01-17T18:20:00+08:00 | us-west | 62.0 | 18.5 | 19.5 | |
| 134 | +| 2024-01-17T21:20:00+08:00 | us-east | 63.0 | 18.0 | 19.0 | |
| 135 | +| 2024-01-18T00:20:00+08:00 | us-central | 61.5 | 19.0 | 19.5 | |
| 136 | +| 2024-01-18T03:20:00+08:00 | eu-west | 62.5 | 17.5 | 20.0 | |
| 137 | +| 2024-01-18T06:20:00+08:00 | ap-south | 63.5 | 17.0 | 19.5 | |
| 138 | ++---------------------------+------------+------------+--------------+------------+ |
| 139 | +``` |
| 140 | + |
| 141 | +将 `region` 和 `time` 作为分组列,使用 `date_bin_gapfill` 对数据进行分组以及窗口补全, |
| 142 | +查询 `region = 'eu-west'` 分组内 `usage_user`、`usage_system`、`usage_idle` 三个列的平均值: |
| 143 | + |
| 144 | +``` text |
| 145 | ++---------------------------+---------+---------------------+-----------------------+---------------------+ |
| 146 | +| bin | region | avg(cpu.usage_user) | avg(cpu.usage_system) | avg(cpu.usage_idle) | |
| 147 | ++---------------------------+---------+---------------------+-----------------------+---------------------+ |
| 148 | +| 2024-01-16T08:00:00+08:00 | eu-west | | | | |
| 149 | +| 2024-01-16T11:00:00+08:00 | eu-west | | | | |
| 150 | +| 2024-01-16T14:00:00+08:00 | eu-west | 58.0 | 22.0 | 20.0 | |
| 151 | +| 2024-01-16T17:00:00+08:00 | eu-west | | | | |
| 152 | +| 2024-01-16T20:00:00+08:00 | eu-west | | | | |
| 153 | +| 2024-01-16T23:00:00+08:00 | eu-west | | | | |
| 154 | +| 2024-01-17T02:00:00+08:00 | eu-west | | | | |
| 155 | +| 2024-01-17T05:00:00+08:00 | eu-west | | | | |
| 156 | +| 2024-01-17T08:00:00+08:00 | eu-west | 61.0 | 19.5 | 19.5 | |
| 157 | +| 2024-01-17T11:00:00+08:00 | eu-west | | | | |
| 158 | +| 2024-01-17T14:00:00+08:00 | eu-west | | | | |
| 159 | +| 2024-01-17T17:00:00+08:00 | eu-west | | | | |
| 160 | +| 2024-01-17T20:00:00+08:00 | eu-west | | | | |
| 161 | +| 2024-01-17T23:00:00+08:00 | eu-west | | | | |
| 162 | +| 2024-01-18T02:00:00+08:00 | eu-west | 62.5 | 17.5 | 20.0 | |
| 163 | +| 2024-01-18T05:00:00+08:00 | eu-west | | | | |
| 164 | ++---------------------------+---------+---------------------+-----------------------+---------------------+ |
| 165 | +``` |
| 166 | + |
| 167 | +在以上查询中加入插值函数,使用 `interpolate`、`locf`、`value` 插值函数分别对 `usage_user`、`usage_system`、`usage_idle` 列的平均值,进行填充: |
| 168 | + |
| 169 | +``` text |
| 170 | ++---------------------------+---------+----------------------------------+-----------------------------+----------------------------------------+ |
| 171 | +| window | region | interpolate(avg(cpu.usage_user)) | locf(avg(cpu.usage_system)) | value(avg(cpu.usage_idle),Float64(25)) | |
| 172 | ++---------------------------+---------+----------------------------------+-----------------------------+----------------------------------------+ |
| 173 | +| 2024-01-16T08:00:00+08:00 | eu-west | | | 25.0 | |
| 174 | +| 2024-01-16T11:00:00+08:00 | eu-west | | | 25.0 | |
| 175 | +| 2024-01-16T14:00:00+08:00 | eu-west | 58.0 | 22.0 | 20.0 | |
| 176 | +| 2024-01-16T17:00:00+08:00 | eu-west | 58.5 | 22.0 | 25.0 | |
| 177 | +| 2024-01-16T20:00:00+08:00 | eu-west | 59.0 | 22.0 | 25.0 | |
| 178 | +| 2024-01-16T23:00:00+08:00 | eu-west | 59.5 | 22.0 | 25.0 | |
| 179 | +| 2024-01-17T02:00:00+08:00 | eu-west | 60.0 | 22.0 | 25.0 | |
| 180 | +| 2024-01-17T05:00:00+08:00 | eu-west | 60.5 | 22.0 | 25.0 | |
| 181 | +| 2024-01-17T08:00:00+08:00 | eu-west | 61.0 | 19.5 | 19.5 | |
| 182 | +| 2024-01-17T11:00:00+08:00 | eu-west | 61.25 | 19.5 | 25.0 | |
| 183 | +| 2024-01-17T14:00:00+08:00 | eu-west | 61.5 | 19.5 | 25.0 | |
| 184 | +| 2024-01-17T17:00:00+08:00 | eu-west | 61.75 | 19.5 | 25.0 | |
| 185 | +| 2024-01-17T20:00:00+08:00 | eu-west | 62.0 | 19.5 | 25.0 | |
| 186 | +| 2024-01-17T23:00:00+08:00 | eu-west | 62.25 | 19.5 | 25.0 | |
| 187 | +| 2024-01-18T02:00:00+08:00 | eu-west | 62.5 | 17.5 | 20.0 | |
| 188 | +| 2024-01-18T05:00:00+08:00 | eu-west | | 17.5 | 25.0 | |
| 189 | ++---------------------------+---------+----------------------------------+-----------------------------+----------------------------------------+ |
| 190 | +``` |
0 commit comments