先日、InfluxDB v1.2がリリースされ、サブクエリが使えるようになったので、早速試してみました。
[InfluxDB 1.2 released with subqueries and 50% better write throughput on larger hardware]
(https://www.influxdata.com/influxdb-1-2-released-with-subqueries-and-50-better-write-performance-on-larger-hardware/)
サブクエリとは
v1.1までのInfluxDBでは、SQLライクに複数のフィールドの値を計算できるものの、集計関数の中には単一の値しか書くことが出来ませんでした。
o select value1 * 100 from ... # OK
x select mean(value1 * 100) from ... # 関数の中には計算式を書けない
o select mean(value1) * 100 from ... # これはOK
x select mean(value1 * value2) from ...
o select mean(value1) * mean(value2) from ... # 関数の結果を計算はできるがやりたいのはコレジャナイ
上記のような計算を行う場合、従来は(value1 * value2)
のクエリの計算結果を一旦measurementとして保存し、その結果に対して再度クエリをかけて平均を取る、ということを行う必要がありました。しかしv1.2でサポートされたサブクエリを使うと、同等のことが1回のクエリで可能になります。
select mean(value) from (select value1 * value2 from ...)
使用例その1: 加重平均
まずは上記で例に挙げたような加重平均を試してみます。サンプルデータは下記のとおり。(表示を見やすくするため、precision rfc3339
としています)
> select * from sample_data
name: sample_data
time count host value
---- ----- ---- -----
2017-01-26T00:00:00Z 33 host1 0.1686618
2017-01-26T00:00:00Z 10 host2 0.772844364
2017-01-26T00:01:00Z 60 host1 0.025078533
2017-01-26T00:01:00Z 86 host2 0.589876001
2017-01-26T00:02:00Z 28 host1 0.795133127
2017-01-26T00:02:00Z 41 host2 0.801407917
2017-01-26T00:03:00Z 91 host1 0.081822447
2017-01-26T00:03:00Z 90 host2 0.765902936
2017-01-26T00:04:00Z 61 host1 0.51287518
2017-01-26T00:04:00Z 38 host2 0.53270741
2017-01-26T00:05:00Z 51 host1 0.060094054
2017-01-26T00:05:00Z 79 host2 0.128055132
2017-01-26T00:06:00Z 72 host1 0.190071427
2017-01-26T00:06:00Z 35 host2 0.005363927
2017-01-26T00:07:00Z 25 host1 0.211173586
2017-01-26T00:07:00Z 61 host2 0.194961101
2017-01-26T00:08:00Z 41 host1 0.211522929
2017-01-26T00:08:00Z 16 host2 0.022634187
2017-01-26T00:09:00Z 75 host1 0.131138756
2017-01-26T00:09:00Z 89 host2 0.819108491
countを、各valueに対する重み値とすると、重み付けした値(value * count
)は問題なく計算できます。
> select host, value * count as weighed_value from sample_data
name: sample_data
time host weighed_value
---- ---- -------------
2017-01-26T00:00:00Z host1 5.5658394
2017-01-26T00:00:00Z host2 7.72844364
2017-01-26T00:01:00Z host1 1.50471198
2017-01-26T00:01:00Z host2 50.729336086
2017-01-26T00:02:00Z host1 22.263727556000003
2017-01-26T00:02:00Z host2 32.857724597
2017-01-26T00:03:00Z host1 7.445842677000001
2017-01-26T00:03:00Z host2 68.93126424
2017-01-26T00:04:00Z host1 31.28538598
2017-01-26T00:04:00Z host2 20.24288158
2017-01-26T00:05:00Z host1 3.064796754
2017-01-26T00:05:00Z host2 10.116355427999999
2017-01-26T00:06:00Z host1 13.685142743999998
2017-01-26T00:06:00Z host2 0.187737445
2017-01-26T00:07:00Z host1 5.27933965
2017-01-26T00:07:00Z host2 11.892627161
2017-01-26T00:08:00Z host1 8.672440089
2017-01-26T00:08:00Z host2 0.362146992
2017-01-26T00:09:00Z host1 9.8354067
2017-01-26T00:09:00Z host2 72.900655699
ここから、各時刻における全ホスト間の平均値は、元のクエリをfrom句にいれて、以下のように計算できます。
> select mean(*) from (select host, value * count as weighed_value from sample_data) where time >= '2017-01-26T00:00:00Z' and time < '2017-01-26T00:10:00Z' group by time(1m)
name: sample_data
time mean_weighed_value
---- ------------------
2017-01-26T00:00:00Z 6.64714152
2017-01-26T00:01:00Z 26.117024033000003
2017-01-26T00:02:00Z 27.560726076500004
2017-01-26T00:03:00Z 38.1885534585
2017-01-26T00:04:00Z 25.76413378
2017-01-26T00:05:00Z 6.590576090999999
2017-01-26T00:06:00Z 6.936440094499999
2017-01-26T00:07:00Z 8.5859834055
2017-01-26T00:08:00Z 4.5172935405
2017-01-26T00:09:00Z 41.368031199499995
それぞれの時刻において、host1とhost2の平均値となっています。
また、各ホスト毎に10分間の平均値も、下記のようにして計算できます。
> select mean(*) from (select host, value * count as weighed_value from sample_data) where time >= '2017-01-26T00:00:00Z' and time < '2017-01-26T00:10:00Z' group by time(10m),host
name: sample_data
tags: host=host1
time mean_new_value
---- --------------
2017-01-26T00:00:00Z 10.860263353000002
name: sample_data
tags: host=host2
time mean_new_value
---- --------------
2017-01-26T00:00:00Z 27.5949172868
使用例その2: 累積値
ネットワークのトラフィック等をSNMPで取得すると累積値として結果が得られますが、これもInfluxDBでは扱いづらいデータでした。
> select * from sample_data
name: sample_data
time host value
---- ---- -----
2017-01-25T23:59:00Z host1 0
2017-01-25T23:59:00Z host2 0
2017-01-26T00:00:00Z host1 0.380175335
2017-01-26T00:00:00Z host2 0.654674526
2017-01-26T00:01:00Z host1 0.548469287
2017-01-26T00:01:00Z host2 1.518483451
2017-01-26T00:02:00Z host1 0.912088251
2017-01-26T00:02:00Z host2 1.618768565
2017-01-26T00:03:00Z host1 1.024910481
2017-01-26T00:03:00Z host2 1.661952017
2017-01-26T00:04:00Z host1 1.194558728
2017-01-26T00:04:00Z host2 2.532767878
2017-01-26T00:05:00Z host1 1.518409392
2017-01-26T00:05:00Z host2 3.402324839
2017-01-26T00:06:00Z host1 1.603926464
2017-01-26T00:06:00Z host2 4.058450398
2017-01-26T00:07:00Z host1 2.06296154
2017-01-26T00:07:00Z host2 4.794882977
2017-01-26T00:08:00Z host1 2.408185365
2017-01-26T00:08:00Z host2 4.902904745
2017-01-26T00:09:00Z host1 3.351145834
2017-01-26T00:09:00Z host2 4.915808337
derivative
関数を使うと差分を計算できますが、その結果をさらに集計する、という事が従来は出来ませんでした。
> select derivative(value,1m) from sample_data group by host
name: sample_data
tags: host=host1
time derivative
---- ----------
2017-01-26T00:00:00Z 0.380175335
2017-01-26T00:01:00Z 0.16829395199999997
2017-01-26T00:02:00Z 0.36361896400000004
2017-01-26T00:03:00Z 0.11282223000000002
2017-01-26T00:04:00Z 0.16964824700000003
2017-01-26T00:05:00Z 0.32385066399999984
2017-01-26T00:06:00Z 0.08551707200000003
2017-01-26T00:07:00Z 0.45903507599999993
2017-01-26T00:08:00Z 0.34522382500000015
2017-01-26T00:09:00Z 0.942960469
name: sample_data
tags: host=host2
time derivative
---- ----------
2017-01-26T00:00:00Z 0.654674526
2017-01-26T00:01:00Z 0.8638089250000001
2017-01-26T00:02:00Z 0.10028511400000006
2017-01-26T00:03:00Z 0.043183451999999845
2017-01-26T00:04:00Z 0.8708158610000001
2017-01-26T00:05:00Z 0.8695569609999998
2017-01-26T00:06:00Z 0.6561255589999999
2017-01-26T00:07:00Z 0.7364325790000006
2017-01-26T00:08:00Z 0.10802176799999952
2017-01-26T00:09:00Z 0.012903591999999797
複数ホストがある中で、最大、最小の値を取得したい場合、サブクエリを使うと以下のように書くことが出来ます。
> select max(derivative) as max, min(derivative) as min from (select derivative(value,1m) from sample_data group by host) where time >= '2017-01-26T00:00:00Z' and time < '2017-01-27T00:00:00Z' group by time(1m) fill(none)
name: sample_data
time max min
---- --- ---
2017-01-26T00:00:00Z 0.654674526 0.380175335
2017-01-26T00:01:00Z 0.8638089250000001 0.16829395199999997
2017-01-26T00:02:00Z 0.36361896400000004 0.10028511400000006
2017-01-26T00:03:00Z 0.11282223000000002 0.043183451999999845
2017-01-26T00:04:00Z 0.8708158610000001 0.16964824700000003
2017-01-26T00:05:00Z 0.8695569609999998 0.32385066399999984
2017-01-26T00:06:00Z 0.6561255589999999 0.08551707200000003
2017-01-26T00:07:00Z 0.7364325790000006 0.45903507599999993
2017-01-26T00:08:00Z 0.34522382500000015 0.10802176799999952
2017-01-26T00:09:00Z 0.942960469 0.012903591999999797
また、各ホスト毎に、10分間の最大値、最小値も取得可能です。
> select max(derivative) as max, min(derivative) as min from (select derivative(value,1m) from sample_data group by host) where time >= '2017-01-26T00:00:00Z' and time < '2017-01-27T00:00:00Z' group by time(10m),host fill(none)
name: sample_data
tags: host=host1
time max min
---- --- ---
2017-01-26T00:00:00Z 0.942960469 0.08551707200000003
name: sample_data
tags: host=host2
time max min
---- --- ---
2017-01-26T00:00:00Z 0.8708158610000001 0.012903591999999797