[BUG] clickhouse: getTimeSeriesData drops dimension columns, collapsing long-format results into one series
メンテナーはふだん 1 日以内に返信
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 58/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- typescript
調査の方向性
Start with clickhouse/src/queries/click-house-time-series-query/get-click-house-data.ts:26-48 and compare its transformation with greptimedb/src/queries/greptimedb-time-series-query/get-greptimedb-data.ts:124-143. Implement the stated partitioning and pivot behavior while preserving wide-result handling, then verify that dimension labels, grouped series, and multi-metric names match the proposed contract without changing the separate time-less case in #841.
索引モデルが issue の本文から書いたものです。
説明
Summary
ClickHouseTimeSeriesQuery.getTimeSeriesData() treats every column except time as a numeric metric column. Any string/dimension column is coerced with Number(), becomes null, and is then removed by the "drop all-null series" filter. For long-format (a.k.a. tall) SQL — the shape documented for the Grafana ClickHouse datasource this plugin is a migration target for — the dimension is silently destroyed and every series collapses into a single anonymous series.
Repro
SELECT toStartOfInterval(now(), INTERVAL 300 second) AS time,
machine AS series,
count() AS value
FROM system.query_log
GROUP BY time, series
ORDER BY time, series
Returned rows (abridged):
| time | series | value |
|---|---|---|
| 2026-09-29 12:00:00 | node-a | 41 |
| 2026-09-29 12:00:00 | node-b | 38 |
| 2026-09-29 12:05:00 | node-a | 44 |
| 2026-09-29 12:05:00 | node-b | 36 |
Expected: 2 series — node-a and node-b — each with 2 points.
Actual: 1 series named value with 4 points and duplicated timestamps (a zig-zag), because both machine and the per-node separation are gone.
Cause
clickhouse/src/queries/click-house-time-series-query/get-click-house-data.ts:26-48
const metricNames = Object.keys(data[0] ?? {}).filter((key) => key !== 'time'); // line 32
return metricNames
.map((metricName) => {
const values: Array<[number, number | null]> = data.map((row) => {
const timestamp = new Date(row.time).getTime();
const value = toTimeSeriesValue(row[metricName]); // Number('node-a') -> NaN -> null
return [timestamp, value];
});
return { name: metricName, values };
})
.filter((series) => series.values.some(([, value]) => value !== null)); // line 47: series dropped
There is no pivot step: the plugin can only express one series per column, never one series per (dimension, column).
Knock-on effect:
labelsis never populated, solegend/labels-based features (andTable) have nothing to render. Note the log query does setlabels(get-click-house-log-data.ts:62), so the contract is already understood elsewhere in the plugin, and the GreptimeDB plugin in this repo already pivots non-value columns intolabels(greptimedb/src/queries/greptimedb-time-series-query/get-greptimedb-data.ts:124-143).
(inferStepMs() is not affected: it sorts timestamps and skips non-positive deltas, so [t0, t0, t1, t1] still yields the correct step. Correcting an earlier claim of mine in this issue.)
Scope
We migrated 215 Grafana dashboards (Grafana + grafana-clickhouse-datasource → Perses) and replayed every query through the plugin's real transport:
| queries | |
|---|---|
| lose ≥1 column | 174 / 215 (81%) |
| dimension with ≥2 distinct values collapsed — chart/table is wrong | 109 |
| only the legend label lost (data still correct) | 65 |
| fully clean | 26 |
Per panel kind: TimeSeriesChart 73/141 broken, Table 30/30, GaugeChart 3/3, BarChart/PieChart/LogsTable 4/4, StatChart 1/37.
Real examples of the collapsed dimension:
| dashboard / panel | dropped column | distinct values |
|---|---|---|
baremetal-hosts "Network throughput" |
series |
244 (141 672 rows) |
ci-github-actions "Jobs completed per day" |
repository |
27 |
ceph-health "Stored per pool" |
series |
9 |
k8s-namespace-efficiency (37 namespaces) |
namespace column | 37 |
Compatibility note
grafana-clickhouse-datasource documents this exact shape — README, "Multi-line time series": "field 1: datetime field with an alias of time; field 2: value to group by; field 3+: the metric values" — and Grafana's own Time series dimensions describes building labels from the string columns of a tall result. $__columns(timeColumn, key, value) in the Grafana plugin expands to precisely this shape ("one series per key value").
Proposed behaviour
Detect dimension columns instead of assuming "everything except time is numeric":
- Partition the result columns into
time(a column namedtime— the alias the Grafana plugin itself requires to recognise a time series),numeric(every value isnull | '' | finite number) anddimension(the rest). - No dimension columns → keep the current behaviour exactly (wide results keep working; this is the 26 clean queries).
- ≥1 dimension column → pivot: group rows by the stringified dimension columns and emit one series per group, following the naming already used by the GreptimeDB plugin in this repo (
buildSeriesName:key=value,key=value):labels={ <dimColumn>: <value>, ... };- one numeric column →
name=key=value,...; - several numeric columns → one series per (dimension, numeric column),
name=key=value,... <valueColumn>and the value column also recorded inlabelsso row-oriented consumers (Table) can tell the rows apart.
- Results with no
timecolumn at all are handled in #841.
time-less results (pure table queries, e.g. SELECT app, team, count() FROM ... GROUP BY app, team) currently hit new Date(undefined).getTime() → NaN for every point and end up as a single series holding only the last row — that is filed separately in #841.
Environment
@perses-dev/clickhouse-plugin0.6.0and0.7.0-beta.6— behaviour is identical in both.- Perses
0.54.0.
- 主要言語
- TypeScript
- スター
- 33
- フォーク
- 91
- 平均マージ
- 1日 17時間
- マージ済み PR(30日)
- 37
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドなし
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
perses/plugins のほかの issue
-
[BUG] splunk: export parsing, job polling and missing values are not handled robustly対応中かも @AnKiT-GaRG2 が 5 日前に担当しました。 オープン
難易度 3/5 1〜2日 初心者へのやさしさ 35/100
メンテナーはふだん 1 日以内に返信
-
[BUG] clickhouse: FORMAT substring check, envelope fallback and swallowed errors対応中かも @Yash121l が 21 日前に担当しました。 オープン
難易度 4/5 3〜5日 初心者へのやさしさ 55/100
perses/plugins#842 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 3/5 1〜2日 初心者へのやさしさ 75/100
メンテナーはふだん 1 日以内に返信
-
bug
難易度 5/5 1週間以上 初心者へのやさしさ 35/100
perses/plugins#501 · コメント 5 件 ·
メンテナーはふだん 1 日以内に返信
-
Module federation warnings "No required version specified"再び着手できるかも このイシューのプルリクエストはマージされずにクローズされました。 オープン
難易度 3/5 1〜2日 初心者へのやさしさ 35/100
メンテナーはふだん 1 日以内に返信
似ている issue
-
triage
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信
-
🎙️ task - drop the raw `./node_modules/.bin/rhachet roles boot` line from bhuild's feedback templateオープン
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
ehmpathy/rhachet-roles-bhuild#639 ·
メンテナーはふだん 1 日以内に返信
-
e2e-failure ready-to-code
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
redhat-developer/rhdh-plugin-export-overlays#4650 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
メンテナーはふだん 13 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
omdsh-dev/DSH-better-sidebar#1098 ·
メンテナーはふだん 2 日以内に返信