[Feature] BanyanDB: BydbQL surface, integration fixtures, docs for tag aggregation
Author: hanahmilyCreated Sep 17, 2026Updated Sep 17, 2026
Labelsfeaturedatabase
Part 4 of 5 of the tag aggregation and time bucketing design, shipped in apache/skywalking-banyandb#1360.
Design references: §5.4 BydbQL · §10 Compatibility (limit) · §11 Testing strategy · §12 Delivery order (stages 7–8)
Depends on: #14089 (time-bucket grouping) and #14090 (COUNT_DISTINCT) — this issue makes both reachable from BydbQL and proves them end to end together.
Scope
BydbQL
COUNT(DISTINCT col)—DISTINCTvalid insideCOUNTonly;SUM(DISTINCT col)is a parse error.- Aggregate column resolves against tags as well as fields (
convertAggregationcurrently hard-errors outsideallFields). TIME_BUCKET(<duration>)pseudo-column, valid only inGROUP BY, at most once, argument optional (empty → the measure's own interval); not selectable in the projection.bydbctlTUI planner constant so the plan renders the new function/pseudo-column.
Integration
- The load-bearing multi-bucket cardinality fixture (one user × 3 api-keys / 3 hour buckets, a second user × 2), asserting the scalar case and the correct order for the ranked+paged case — run in both
test/integration/distributed/query/vectorized_test.go(liaison + 2 data nodes) and standalone. - The same fixture reused at a second bucket width, to catch a bucket key that's computed but ignored.
- The decomposition oracle: a bucketed query over a window must equal the union of per-bucket queries over the same window, row-for-row on
(bucket, tags…)— each per-bucket query is independently trustworthy, so this is a real oracle rather than a golden file. data.go's golden comparison currently ignores timestamps; these new cases need it included, or every bucket silently collapses to zero and the suite still passes.- The generated feature matrix (
test/cases/measure/cmd/generate/layer3_features.go,ql_renderer.go) gains the sixth aggregate function — it's hard-coded today and won't be caught by theexhaustivelinter (the switches havedefaultbranches).
Docs
docs/interacting/bydbql.md: the new grammar, and prominently, thelimit-with-bucketing note (default 100 truncates a bucketed series — this must be visible in the docs, not just the API reference).docs/api-reference.mdregenerated, never hand-edited.
Out of scope
- The optional local-scan performance follow-up (run-folding, metadata-only scan) — separate issue.
Test / Definition of done
- Parser:
COUNT(DISTINCT x)parses;SUM(DISTINCT x)errors;TIME_BUCKET()/TIME_BUCKET('5m')both parse; a secondTIME_BUCKETin oneGROUP BYerrors;TIME_BUCKETinSELECTerrors. - Binder/transformer
protocmpequivalence tests against the equivalent hand-builtQueryRequest. bydbctlplanner test rendering a query using both features.- The integration fixtures above green in standalone and distributed CI.
- Doc diff reviewed specifically for the
limitcallout.
Source: apache/skywalking