Semantic Measures and Metrics
A measure is syntax; a metric is a contract
Measure = an aggregation expression; metric = the named, documented, testable business quantity built from measures and dims. Learn the vocabulary that makes a layer rigorous.
What you will learn
- Distinguish measures from metrics and dims
- Write a metrics definition with filters, time and format
- Test a metric definition like code
What is this?
In a semantic layer, a measure is a reusable aggregation expression (SUM(amount), COUNT(DISTINCT id)) computed over a model. A metric is a named, typed, documented business quantity — Revenue, Orders, Active Customers — assembled from measures, dims, optional filters and time grains, with owners and tests. Measures are pieces; metrics are the contract consumers sign.
Why do you need it?
- The distinction keeps layers composable and reviewable.
- Named metrics with owners are governable; ad-hoc expressions aren't.
- Time grain, filters and defaults are part of a metric's definition—not an afterthought bolt-on.
- Interviewers probe exactly this vocabulary at the senior level.
Mental model
Kitchen staples vs menu dishes
Measures vs metrics
Flour, eggs and stock are staples — reusable pieces (measures). 'Coq au Vin' is a named, plated dish with a recipe (metric): fixed composition, name, portion, cost. You cook staples into dishes; you compose measures into metrics.
How it works
- Measures: aggregation + target column (+ optional filter) — building blocks.
- Metrics: name, description, measure, grain/time, optional filters and owners.
- Dims attach: every metric slices by the layer's conformed dims.
- Formatting, rounding and defaults are metadata on the metric.
- Tests: metric-level checks (values in range, totals reconcile, freshness) run in CI.
From measure to governed metric.
Examples
Measure vs metric in a sessionable format
-- MEASURE (piece):measure: amount_sum { aggregation: SUM expr: fact_sales.amount labels: ["total_amount"]} -- METRIC (contract):metric: revenue { description: "Gross revenue of shipped orders" type: number label: "Revenue" name: revenue type_params: measure: amount_sum filters: - expr: fact_sales.status = 'shipped' owner: finance tags: [kpi, certified]}The measure defines how to aggregate; the metric defines what it means, how to filter, who owns it and which tags govern it.
In production
- A finance 'Revenue' metric filters to shipped orders; every report inherits the filter.
- An 'Active Customers' metric counts distinct customers per date with a 90-day lookback.
- Formatting metadata ('Currency USD, 2dp') ships with the metric so every export matches.
Best practices
- Write metrics as named, owned, documented objects — never bare expressions.
- Encode business rules (filters, time grain) inside the metric, not in reports.
- Tag certified vs experiment metrics so consumers know trust level.
- Test each metric against a source control total in CI.
Common mistakes
- Renaming a raw measure and calling it a metric — no contract.
- Filters living in reports instead of the metric definition.
- No owner/tag — a metric nobody owns gets changed by everyone.
- Typing everything as floats without format, so exports drift.
Debugging tips
- A metric differs between consumers → someone's applying extra filters; check both queries' filter provenance.
- Wrong totals → inspect the measure aggregation and its filter set.
- Freshness silent → add the metric-level freshness test.
Interview checkpoint
Quick quiz
Which is the named, documented, owned business quantity?
Business filters belong inside the metric definition, not in every report.