Dimensions
Dimensions represent the non-aggregatable columns in your data set, which are the attributes, features, or characteristics that describe or categorize data. In the context of the Semantic Layer, dimensions are part of a larger structure called a semantic model. They are created along with other elements like entities and simple metrics and used to add more details to your data. In SQL, dimensions are typically included in the group by clause of your SQL query.
All dimensions require a name, type, and can optionally include an expr parameter. The name for your Dimension must be unique within the same semantic model.
| Parameter | Description | Required | Type |
|---|---|---|---|
name | The name of the dimension that will be visible to the user in downstream tools. It can also serve as an alias for derived dimensions Dimension names should be unique within a semantic model, but they can be non-unique across different models as MetricFlow uses joins to identify the right dimension. | Required | String |
type | Specifies the type of group created in the semantic model. There are two types: - Categorical: Describe attributes or features like geography or sales region. - Time: Time-based dimensions like timestamps or dates. | Required | String |
description | A clear description of the dimension. | Optional | String |
expr | Defines the underlying column or SQL query for a dimension. If no expr is specified, MetricFlow will use the column with the same name as the group. You can use the column name itself to input a SQL expression. | Optional | String |
label | Defines the display value in downstream tools. Accepts plain text, spaces, and quotes (such as orders_total or "orders_total"). | Optional | String |
meta | Set metadata for a resource and organize resources. Accepts plain text, spaces, and quotes. | Optional | Dictionary |
Refer to the following for the complete specification for dimensions:
models:
- name: Model name # Required
semantic_model:
enabled: true # bool. Required
columns: # Any column can have either an entity or a dimension, but not both
- name: my_dimension_column # Required
description: Column description # Optional
dimension:
name: my_dimension # Optional, defaults to column name
type: categorical # Required. Accepted values: categorical | time
label: Recommended adding a string that defines the display value in downstream tools # Optional
description: Same as always # Optional, defaults to the column description if not otherwise specified
Refer to the following example to see how dimensions are used in a semantic model:
(Applies to dbt v1.12 and later)models:
- name: fact_transactions
semantic_model:
enabled: true
name: transactions
agg_time_dimension: order_date
columns:
# --- entities ---
- name: transaction_column
entity:
type: primary
name: transaction
# --- dimensions tied 1:1 to columns ---
- name: another_transaction_column
granularity: day
dimension:
type: time
name: order_date
label: "Date of transaction"
description: "A record for every transaction that takes place. Carts are considered multiple transactions for each SKU."
- name: type
dimension:
type: categorical
name: type
derived_semantics in dimensions
Use the derived_semantics key in the model YAML entry when you need to derive a dimension definition that is not a direct 1:1 mapping to a single physical column. The expr field is required when using derived_semantics.
models:
- name: my_model
semantic_model:
enabled: true
...
derived_semantics:
dimensions:
- name: is_bulk
type: categorical
expr: "case when quantity > 10 then true else false end" # Required
Dimensions are bound to the primary entity of the semantic model they are defined in.
MetricFlow requires that all semantic models have a primary entity. This is to guarantee unique dimension names. If your data source doesn't have a primary entity, you need to assign the entity a name using the entity key. It doesn't necessarily have to map to a column in that table and assigning the name doesn't affect query generation. We recommend making these "virtual primary entities" unique across your semantic model. See the following example on how to define a primary entity:
models:
- name: bookings_monthly_source
semantic_model:
enabled: true
agg_time_dimension: ds
columns:
# Primary entity
- name: booking_id
entity:
type: primary
name: booking_id
- name: order_date
granularity: day
dimension:
type: time
label: "Date"
metrics:
- name: bookings_monthly
type: simple
agg: sum
If your table doesn't have a physical primary key column, you can still declare a primary entity. Set the model’s grain by declaring a primary_entity. The new YAML spec supports this and treats the model as being at that entity’s grain.
models:
- name: model_without_pk
semantic_model:
enabled: true
primary_entity: order # "virtual primary entity"
columns:
- name: customer_id
entity: foreign
Dimensions types
This section further explains the dimension definitions, along with examples. Dimensions have the following types:
Categorical
Categorical dimensions are used to group metrics by different attributes, features, or characteristics such as product type. They can refer to existing columns in your dbt model or be calculated using a SQL expression with the expr parameter. An example of a categorical dimension is is_bulk_transaction, which is a group created by applying a case statement to the underlying column quantity. This allows users to group or filter the data based on bulk transactions.
dimensions:
- name: is_bulk_transaction
type: categorical
expr: case when quantity > 10 then true else false end
config:
meta:
usage: "Filter to identify bulk transactions, like where quantity > 10."
Time
(Applies to dbt v1.12 and later)Time dimensions no longer use type_params.
- For dimensions defined on a column entry, add the column’s
granularityat the column level. - For derived dimensions, add
granularityin the dimension configuration.
A semantic model’s default aggregation time dimension is set with the agg_time_dimension property at the model's top level. A metric can override this with its own agg_time_dimension. For more information, see Migrate to the latest YAML spec.
You can use multiple time groups in separate metrics. For example, the users_created metric uses created_at, and the users_deleted metric uses deleted_at:
# dbt users
dbt sl query --metrics users_created,users_deleted --group-by metric_time__year --order-by metric_time__year
# dbt Core users
mf query --metrics users_created,users_deleted --group-by metric_time__year --order-by metric_time__year
You can set is_partition for time to define specific time spans.
- is_partition
- time_granularity
Use is_partition: True to show that a dimension exists over a specific time window. For example, a date-partitioned dimensional table. When you query metrics from different tables, the Semantic Layer uses this parameter to ensure that the correct dimensional values are joined to measures.
models:
- name: orders
semantic_model:
enabled: true
agg_time_dimension: created_at
columns:
- name: ts_created
granularity: day
dimension:
type: time
name: created_at
label: "Date of creation"
config:
meta:
notes: "Only valid for orders from 2022 onward"
is_partition: true
- name: ts_deleted
granularity: day
dimension:
type: time
name: deleted_at
label: "Date of deletion"
is_partition: true
metrics:
- name: users_deleted
type: simple
agg: sum
expr: 1
agg_time_dimension: deleted_at
- name: users_created
type: simple
agg: sum
expr: 1
granularity specifies the grain of a time dimension. MetricFlow will transform the underlying column to the specified granularity. For example, if you add hourly granularity to a time dimension column, MetricFlow will run a date_trunc function to convert the timestamp to hourly. You can easily change the time grain at query time and aggregate it to a coarser grain, for example, from hourly to monthly. However, you can't go from a coarser grain to a finer grain (monthly to hourly).
Our supported granularities are:
- nanosecond (Snowflake only)
- microsecond
- millisecond
- second
- minute
- hour
- day
- week
- month
- quarter
- year
Aggregation between metrics with different granularities is possible, with the Semantic Layer returning results at the coarsest granularity by default. For example, when querying two metrics with daily and monthly granularity, the resulting aggregation will be at the monthly level.
models:
- name: your_model_name
semantic_model:
enabled: true
agg_time_dimension: created_at
columns:
- name: ts_created
granularity: hour
dimension:
type: time
name: created_at
label: "Date of creation"
is_partition: true
- name: ts_deleted
granularity: day
dimension:
type: time
name: deleted_at
label: "Date of deletion"
is_partition: true
metrics:
- name: users_deleted
type: simple
agg: sum
expr: 1
agg_time_dimension: deleted_at
- name: users_created
type: simple
agg: sum
expr: 1
SCD Type II
(Applies to dbt v1.12 and later)Currently, semantic models with SCD Type II dimensions cannot contain simple metrics.
MetricFlow supports joins against dimensions values in a semantic model built on top of a slowly changing dimension (SCD) Type II table. This is useful when you need a particular metric sliced by a group that changes over time, such as the historical trends of sales by a customer's country.
Basic structure
SCD Type II are groups that change values at a coarser time granularity. SCD Type II tables typically have two time columns that indicate the validity period of a dimension: valid_from (or tier_start) and valid_to (or tier_end). This creates a range of valid rows with different dimension values for a metric.
MetricFlow associates the metric with the earliest available dimension value within a coarser time window, such as a month. By default, it uses the group valid at the start of this time granularity.
MetricFlow supports the following basic structure of an SCD Type II data platform table:
| entity_key | dimensions_1 | dimensions_2 | ... | dimensions_x | valid_from | valid_to |
|---|---|---|---|---|---|---|
| 123 | value_a | value_x | ... | value_n | 2024-01-01 | 2024-06-30 |
| 123 | value_b | value_y | ... | value_m | 2024-07-01 | 2024-12-31 |
entity_key(required): A unique identifier for each row in the table, such as a primary key or another unique identifier specific to the entity.valid_from(required): Start date timestamp for when the dimension is valid. Usevalidity_params: is_start: Truein the semantic model to specify this.valid_to(required): End date timestamp for when the dimension is valid. Usevalidity_params: is_end: Truein the semantic model to specify this.
Semantic model parameters and keys
When configuring an SCD Type II table in a semantic model, use validity_params to specify the start (valid_from) and end (valid_to) of the validity window for each dimension.
validity_params: Parameters that define the validity window.is_start: True: Indicates the start of the validity period. Displayed asvalid_fromin the SCD table.is_end: True: Indicates the end of the validity period. Displayed asvalid_toin the SCD table.
Here’s an example configuration:
(Applies to dbt v1.12 and later)models:
- name: tiers
semantic_model:
enabled: true
agg_time_dimension: tier_start
columns:
- name: start_date
granularity: day
dimension:
type: time # The type of dimension
name: tier_start # The name of the dimension.
label: "Start date of tier" # A readable label for the dimension
validity_params: # Defines the validity window
is_start: true # Indicates the start of the validity period
- name: end_date
granularity: day
dimension:
type: time
name: tier_end
label: "End date of tier"
validity_params:
is_end: true # Indicates the end of the validity period
SCD Type II tables have a specific dimension with a start and end date. To join tables:
- Set the additional entity
typeparameter to thenaturalkey. - Use a
naturalkey as an entitytype, which means you don't need aprimarykey. - In most instances, SCD tables don't have a logically usable
primarykey becausenaturalkeys map to multiple rows.
Implementation
Here are some guidelines to follow when implementing SCD Type II tables:
- The SCD table must have
valid_toandvalid_fromtime dimensions, which are logical constructs. - The
valid_fromandvalid_toproperties must be specified exactly once per SCD table configuration. - The
valid_fromandvalid_toproperties shouldn't be used or specified on the same time dimension. - The
valid_fromandvalid_totime dimensions must cover a non-overlapping period where one row matches each natural key value (meaning they must not overlap and should be distinct). - We recommend defining the underlying dbt model with dbt snapshots. This supports the SCD Type II table layout and ensures that the table is updated with the latest data.
This is an example of SQL code that shows how a sample metric called num_events is joined with versioned dimensions data (stored in a table called scd_dimensions) using a primary key made up of the entity_key and timestamp columns.
select metric_time, dimensions_1, sum(1) as num_events
from events a
left outer join scd_dimensions b
on
a.entity_key = b.entity_key
and a.metric_time >= b.valid_from
and (a.metric_time < b. valid_to or b.valid_to is null)
group by 1, 2
SCD examples
The following are examples of how to use SCD Type II tables in a semantic model:
Was this page helpful?
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.