先日あるお客様との会話で、膨大なデータをグラフにするのに、pg_cronでaggregation(事前集計)をかけておけば、そのグラフをダッシュボードでインタラクティブにスケールを変更しつつ、少ないデータをfetchするだけで良いので、むっちゃ軽快な動作をするようにできまっせ、という話になった。
で、aggregationの内容はハンズオンラボ用に書いたPL/PGSQLを見てもらえば分かる通り、AVG / MIN / MAXを取るだけなので、折れ線グラフにした時に特徴を表すかというと非常に微妙、という説明をしたところ、そのお客様がLTTB(Largest Triangle Three Buckets)アルゴリズムというのがあって、という情報を提供してくれた。
不勉強なもので知らなかったため調べてみると、Qiitaに書いてくれてる人がいるので、まあそこからたどってGitHubのまとめページに行き着いた。特に難しいことをやってるわけではないのだけれど、残念ながらPL/PGSQLで書いてる人がおらん。PL/PGSQLで書かれてれば、CREATE FUNCTIONしてpg_cronで定期的に呼び出してやりゃイイ訳で、じゃ書くかと午前中から書いて今に至る、と。
![](https://rio.st/wp-content/uploads/sites/4/2024/06/source.png)
![](https://rio.st/wp-content/uploads/sites/4/2024/06/sampled.png)
![](https://rio.st/wp-content/uploads/sites/4/2024/06/20240625143925-1024x473.png)
GitHubに放流しておいた。
pg_cronで使うなら、largest_triangle_three_buckets()にクエリ結果とthresholdを引数として渡すように変更すればよろし。
追記:sin波をダウンサンプリングするとどうなるのか。
-- 100件にダウンサンプリングするクエリ
WITH selected_data AS (
SELECT array_agg(POINT(x, sin(radians(x)))) AS data_array
FROM generate_series(-180, 180, 0.1) AS x
)
SELECT * FROM largest_triangle_three_buckets(
(SELECT data_array FROM selected_data),
100
);
![](https://rio.st/wp-content/uploads/sites/4/2024/06/sine.png)
![](https://rio.st/wp-content/uploads/sites/4/2024/06/sampled-100.png)
![](https://rio.st/wp-content/uploads/sites/4/2024/06/sampled-50.png)
![](https://rio.st/wp-content/uploads/sites/4/2024/06/sampled-20.png)
![](https://rio.st/wp-content/uploads/sites/4/2024/06/sampled-10.png)
10件でも特徴は分かりそう。