fixed_grain for level metrics - #2532
Open
robinld wants to merge 3 commits into
Open
Conversation
robinld
force-pushed
the
robind/fixed-grain
branch
from
September 9, 2026 21:52
7b33889 to
97ee562
Compare
robinld
marked this pull request as ready for review
September 9, 2026 22:09
robinld
force-pushed
the
robind/fixed-grain
branch
from
September 10, 2026 00:51
97ee562 to
c27a21a
Compare
robinld
force-pushed
the
robind/fixed-grain
branch
from
September 10, 2026 06:35
c27a21a to
9d1b371
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the
fixed_grainhalf of #2245. A base metric can declare the grain at which its aggregate is computed, and DJ broadcasts that value when the query requests a finer grain.This PR is stacked on #2502, which implements the complementary
reaggregatedirection. It can be retargeted tomainafter #2502 lands.fixed_grainhas three forms:[]: compute at the global grain[dimension, ...]: compute at the declared partition grainFor example, querying
total_revenueat a finer grain generates the equivalent of:The inner aggregate computes the query-group contribution. The outer window re-merges those contributions within the declared fixed grain. A non-empty grain produces
OVER (PARTITION BY ...)instead.Implementation
sql/decompose.pyvalidates that the declaration belongs to one freely aggregatable base component, propagates it through decomposition, and rejects a later window over a broadcast value.construction/build_v3/cube_matcher.pyskips a cube that does not materialize a metric's partition dimension, mirroringvalidate_cube_covers_reaggregate_dimensions. A cube that does carry it is used normally.Current constraints
The initial implementation accepts only cases where broadcasting can be expressed without changing the metric's meaning.
COUNT(DISTINCT ...), a multi-component metric (AVG, variance), or a non-decomposable aggregatereaggregatedimension gets. The result stays the shape that was requestedCOALESCE, so a partition naming one group's column is ungroupedMAX/AVGover it are allowed, as is referencing it beside a window — e.g. a trailing sum divided by a global totalRelated fixes
reaggregateandfixed_graindeclarations do not become part of shared measure state or identity.extractedMeasuresloader'sload_only. Reading a field that loader omits raisesMissingGreenleton a cold session, which the batch handler turns into a silent null rather than an error.Out of scope
{hierarchy, drill_up}frameprimitivereaggregategained create/edit fields and node-page display in feat: semi-additive measures #2502; the equivalent forfixed_grainis deferred to a follow-up, so the declaration is currently settable only through deployment specs and the API.Known gaps
POST /nodes/metricvalidation does not yet reject an unresolvable fixed-grain column, although deployment validation does. The invalid declaration is rejected later when a query attempts to use it.Testing
Coverage includes global and partitioned broadcasts, derived ratios, declaration round trips, namespace copying, semantic identity, frozen-measure reuse, GraphQL decomposition loading, window refusal, and cube matching and materialization carrying the broadcast.