ClickHouseでの時系列分析は、標準的なSQLの集計関数とウィンドウ関数を使って実行できます。 時系列データを扱う際には、通常、主に次の3種類のメトリクスが登場します。
- 時間の経過とともに単調に増加するカウンターメトリクス (ページビューやイベント総数など)
- ある時点での測定値を表し、増減するGaugeメトリクス (CPU使用率や温度など)
- 観測値をサンプリングし、バケットごとに件数を数えるヒストグラム (リクエスト時間やレスポンスサイズなど)
これらのメトリクスでよく使われる分析パターンには、期間どうしでの値の比較、累積合計の計算、変化率の算出、分布の分析などがあります。
これらはすべて、集計、sum() OVER のようなウィンドウ関数、そして histogram() のような専用関数を組み合わせることで実現できます。
前期間比の変化
時系列データを分析する際には、期間ごとに値がどのように変化したかを把握する必要がよくあります。
これは、Gauge とカウンターメトリクスのどちらにとっても重要です。
lagInFrame ウィンドウ関数を使うと、前の期間の値を参照して、こうした変化を計算できます。
次のクエリは、"Weird Al" Yankovic の Wikipedia ページの閲覧数について、前日比の変化を計算する例です。 trend カラムには、前日と比べてトラフィックが増加したか (正の値) 、減少したか (負の値) が示され、通常とは異なる急増や急減を特定するのに役立ちます。
SELECT
toDate(time) AS day,
sum(hits) AS h,
lagInFrame(h) OVER (ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS p,
h - p AS trend
FROM wikistat
WHERE path = '"Weird_Al"_Yankovic'
GROUP BY ALL
LIMIT 10;┌────────day─┬────h─┬────p─┬─trend─┐
│ 2015-05-01 │ 3934 │ 0 │ 3934 │
│ 2015-05-02 │ 3411 │ 3934 │ -523 │
│ 2015-05-03 │ 3195 │ 3411 │ -216 │
│ 2015-05-04 │ 3076 │ 3195 │ -119 │
│ 2015-05-05 │ 3450 │ 3076 │ 374 │
│ 2015-05-06 │ 3053 │ 3450 │ -397 │
│ 2015-05-07 │ 2890 │ 3053 │ -163 │
│ 2015-05-08 │ 3898 │ 2890 │ 1008 │
│ 2015-05-09 │ 3092 │ 3898 │ -806 │
│ 2015-05-10 │ 3508 │ 3092 │ 416 │
└────────────┴──────┴──────┴───────┘累積値
カウンターメトリクスは、時間の経過とともに自然に増加していきます。 この累積的な増加を分析するには、ウィンドウ関数 を使って累積合計を計算できます。
次のクエリでは、累積合計を作成する sum() OVER clause を使用して、これを示しています。bar() function は、この増加を視覚的に表します。
SELECT
toDate(time) AS day,
sum(hits) AS h,
sum(h) OVER (ROWS BETWEEN UNBOUNDED PRECEDING AND 0 FOLLOWING) AS c,
bar(c, 0, 50000, 25) AS b
FROM wikistat
WHERE path = '"Weird_Al"_Yankovic'
GROUP BY ALL
ORDER BY day
LIMIT 10;┌────────day─┬────h─┬─────c─┬─b─────────────────┐
│ 2015-05-01 │ 3934 │ 3934 │ █▉ │
│ 2015-05-02 │ 3411 │ 7345 │ ███▋ │
│ 2015-05-03 │ 3195 │ 10540 │ █████▎ │
│ 2015-05-04 │ 3076 │ 13616 │ ██████▊ │
│ 2015-05-05 │ 3450 │ 17066 │ ████████▌ │
│ 2015-05-06 │ 3053 │ 20119 │ ██████████ │
│ 2015-05-07 │ 2890 │ 23009 │ ███████████▌ │
│ 2015-05-08 │ 3898 │ 26907 │ █████████████▍ │
│ 2015-05-09 │ 3092 │ 29999 │ ██████████████▉ │
│ 2015-05-10 │ 3508 │ 33507 │ ████████████████▊ │
└────────────┴──────┴───────┴───────────────────┘レート計算
時系列データを分析する際は、単位時間あたりのイベント数を把握すると便利です。 このクエリは、1時間ごとの合計を1時間の秒数 (3600) で割ることで、1秒あたりのページビュー数を計算します。 棒グラフを見ることで、アクティビティが集中する時間帯を特定できます。
SELECT
toStartOfHour(time) AS time,
sum(hits) AS hits,
round(hits / (60 * 60), 2) AS rate,
bar(rate * 10, 0, max(rate * 10) OVER (), 25) AS b
FROM wikistat
WHERE path = '"Weird_Al"_Yankovic'
GROUP BY time
LIMIT 10;┌────────────────time─┬───h─┬─rate─┬─b─────┐
│ 2015-07-01 01:00:00 │ 143 │ 0.04 │ █▊ │
│ 2015-07-01 02:00:00 │ 170 │ 0.05 │ ██▏ │
│ 2015-07-01 03:00:00 │ 148 │ 0.04 │ █▊ │
│ 2015-07-01 04:00:00 │ 190 │ 0.05 │ ██▏ │
│ 2015-07-01 05:00:00 │ 253 │ 0.07 │ ███▏ │
│ 2015-07-01 06:00:00 │ 233 │ 0.06 │ ██▋ │
│ 2015-07-01 07:00:00 │ 359 │ 0.1 │ ████▍ │
│ 2015-07-01 08:00:00 │ 190 │ 0.05 │ ██▏ │
│ 2015-07-01 09:00:00 │ 121 │ 0.03 │ █▎ │
│ 2015-07-01 10:00:00 │ 70 │ 0.02 │ ▉ │
└─────────────────────┴─────┴──────┴───────┘ヒストグラム
時系列データの代表的な用途の 1 つは、追跡対象のイベントに基づいてヒストグラムを作成することです。
たとえば、総 hits が 10,000 を超えるページのみを対象に、総 hits に応じたページ数の分布を把握したいとします。
この場合、histogram() 関数を使うと、ビンの数に基づいて適応的なヒストグラムを自動的に生成できます。
SELECT
histogram(10)(hits) AS hist
FROM
(
SELECT
path,
sum(hits) AS hits
FROM wikistat
WHERE date(time) = '2015-06-15'
GROUP BY path
HAVING hits > 10000
)
FORMAT Vertical;Row 1:
──────
hist: [(10033,23224.55065359477,60.625),(23224.55065359477,37855.38888888889,15.625),(37855.38888888889,52913.5,3.5),(52913.5,69438,1.25),(69438,83102.16666666666,1.25),(83102.16666666666,94267.66666666666,2.5),(94267.66666666666,116778,1.25),(116778,186175.75,1.125),(186175.75,946963.25,1.75),(946963.25,1655250,1.125)]次に、arrayJoin() を使ってデータを整形し、bar() で可視化できます。
WITH histogram(10)(hits) AS hist
SELECT
round(arrayJoin(hist).1) AS lowerBound,
round(arrayJoin(hist).2) AS upperBound,
arrayJoin(hist).3 AS count,
bar(count, 0, max(count) OVER (), 20) AS b
FROM
(
SELECT
path,
sum(hits) AS hits
FROM wikistat
WHERE date(time) = '2015-06-15'
GROUP BY path
HAVING hits > 10000
);┌─lowerBound─┬─upperBound─┬──count─┬─b────────────────────┐
│ 10033 │ 19886 │ 53.375 │ ████████████████████ │
│ 19886 │ 31515 │ 18.625 │ ██████▉ │
│ 31515 │ 43518 │ 6.375 │ ██▍ │
│ 43518 │ 55647 │ 1.625 │ ▌ │
│ 55647 │ 73602 │ 1.375 │ ▌ │
│ 73602 │ 92880 │ 3.25 │ █▏ │
│ 92880 │ 116778 │ 1.375 │ ▌ │
│ 116778 │ 186176 │ 1.125 │ ▍ │
│ 186176 │ 946963 │ 1.75 │ ▋ │
│ 946963 │ 1655250 │ 1.125 │ ▍ │
└────────────┴────────────┴────────┴──────────────────────┘