Semantic Layer v2 YAML: миграция с v1 (dbt 1.12)
В dbt 1.12 (релиз апрель 2026) Semantic Layer получил v2 YAML spec — significant изменение в том, как описываются semantic_models. Это не просто синтаксическая косметика — это architectural shift в том, как dbt видит отношения между data model (физическая таблица) и semantic model (метрика-layer).
В этом уроке мы детально разберём:
- Что не нравилось в v1 YAML spec.
- Как выглядит v2 spec и в чём improvement.
- Migration path: автоматический (dbt-autofix) и manual.
- Обратная совместимость и timeline.
- Тонкости новых features в v2.
Metric types: simple, ratio, cumulative (dbt II)
Проблемы v1 spec
V1 spec появился в dbt 1.6 (2024). Через 1.5 года использования community обнаружил несколько проблем:
dbt Labs наблюдал эти проблемы через community feedback и в 1.12 представил v2 spec.
V2 spec: подход «nested under models»
В v2 — semantic_model описывается прямо внутри model definition:
# models/_models.yml (v2)
version: 2
models:
- name: fct_orders
description: "Fact table for order analytics"
columns:
- name: order_id
description: "Unique order identifier"
tests:
- not_null
- unique
- name: customer_id
description: "FK to customer"
- name: amount
description: "Order total amount"
- name: order_date
description: "When order was placed"
# Semantic model nested directly под model
semantic_model:
defaults:
agg_time_dimension: order_date
entities:
- name: order_id
type: primary
- name: customer_id
type: foreign
dimensions:
- name: order_date
type: time
type_params:
time_granularity: day
- name: status
type: categorical
measures:
- name: order_amount
agg: sum
expr: amount
Сравнение с v1:
# v1 (old)
# models/_models.yml
version: 2
models:
- name: fct_orders
description: "..."
columns: [...]
# semantic_models/_semantic.yml (отдельный файл)
semantic_models:
- name: orders
description: "..." # дубликат!
model: ref('fct_orders') # explicit link
entities: [...]
dimensions: [...]
measures: [...]
Что изменилось:
- Один файл. model + semantic_model в одном yaml.
- Single source of truth для description. Один раз указан, semantic_model его inherit.
- No explicit
model: ref(...). Это implicit (semantic_model parent modelfct_orders). - No semantic_model
name. Используется model name (fct_orders). - Tests на columns остаются в model, не дублируются в semantic_model.
Backward compatibility: dbt 1.12+ поддерживает оба spec. V1 YAML файлы продолжают работать. V2 YAML — preferred для new development. Через 2-3 versions (dbt 1.14-1.16) v1 может быть deprecated, но это long-term plan.
Полный пример: v1 -> v2 transformation
Реальный пример из проекта.
V1 (старый формат)
models/_orders.yml:
version: 2
models:
- name: fct_orders
description: "Fact orders for analytics"
columns:
- name: order_id
description: "Order PK"
tests:
- not_null
- unique
- name: customer_id
description: "FK customers"
- name: product_id
description: "FK products"
- name: amount
description: "Order amount"
- name: order_date
description: "Date of order"
- name: status
description: "Order status: pending/completed/refunded"
semantic_models/_sm_orders.yml (отдельный файл!):
semantic_models:
- name: orders
description: "Fact orders for analytics" # дубликат описания
model: ref('fct_orders')
defaults:
agg_time_dimension: order_date
entities:
- name: order_id
type: primary
- name: customer_id
type: foreign
- name: product_id
type: foreign
dimensions:
- name: order_date
type: time
type_params:
time_granularity: day
- name: status
type: categorical
measures:
- name: order_amount
agg: sum
expr: amount
- name: order_count
agg: count
expr: order_id
V2 (новый формат)
models/_orders.yml (один файл):
version: 2
models:
- name: fct_orders
description: "Fact orders for analytics"
columns:
- name: order_id
description: "Order PK"
tests:
- not_null
- unique
- name: customer_id
description: "FK customers"
- name: product_id
description: "FK products"
- name: amount
description: "Order amount"
- name: order_date
description: "Date of order"
- name: status
description: "Order status: pending/completed/refunded"
semantic_model:
defaults:
agg_time_dimension: order_date
entities:
- name: order_id
type: primary
- name: customer_id
type: foreign
- name: product_id
type: foreign
dimensions:
- name: order_date
type: time
type_params:
time_granularity: day
- name: status
type: categorical
measures:
- name: order_amount
agg: sum
expr: amount
- name: order_count
agg: count
expr: order_id
semantic_models/_sm_orders.yml — удалить.
Что улучшилось:
- Один файл вместо двух.
- Description указан один раз.
- Tests и semantic в одном месте.
- При renaming model
fct_orders— переименовываем один файл, semantic_model автоматически связан.
V2-only новые features
V2 добавил несколько features, которые сложно/невозможно сделать в v1:
Feature 1: Inherit column descriptions
semantic_model:
dimensions:
- name: order_date
# Описание берётся из model.columns[].description
# Не нужно дублировать.
type: time
type_params:
time_granularity: day
V1 требовал явный description в semantic_model.dimension. V2 inherits.
Feature 2: Reference column tests
models:
- name: fct_orders
columns:
- name: order_id
tests:
- not_null
- unique
semantic_model:
entities:
- name: order_id
type: primary
# Implicitly inherits not_null + unique tests
# MetricFlow знает, что order_id unique -> может optimize joins
V1 requires manual entity-level constraint declarations. V2 inherits.
Feature 3: Embedded saved queries
semantic_model:
saved_queries:
- name: daily_revenue
query_params:
metrics: [revenue]
group_by: [order_date]
V1 saved_queries — отдельный yaml block. V2 — может быть nested.
Feature 4: Materialized measure spans
semantic_model:
measures:
- name: revenue
agg: sum
expr: amount
# Новое в v2:
materialized_span:
granularity: month # MetricFlow precomputes monthly aggregates
retention_days: 365
Это experimental в 1.12, planned для GA в 1.13. Позволяет automated rollup creation.
Migration path
dbt 1.12 поддерживает оба spec. Стратегия миграции:
Option 1: Manual (для маленьких проектов)
# Для каждого semantic_models файла:
1. Открыть models/_models.yml — соответствующая dbt model
2. Открыть semantic_models/_sm.yml
3. Скопировать semantic_models[0] (без name, без model, без description)
4. Paste как semantic_model: nested под models[].
5. Удалить semantic_models/_sm.yml
6. Test: dbt parse, mf validate, mf query
Время: ~5 минут на semantic_model. На проекте 20 semantic_models = 100 минут.
Option 2: Automatic через dbt-autofix
# autofix умеет конвертировать
pip install --upgrade dbt-autofix
# Dry-run сначала
dbt-autofix --target-spec=v2-semantic --dry-run .
# Apply
dbt-autofix --target-spec=v2-semantic .
Autofix:
- Reads semantic_models/*.yml.
- Matches каждый semantic_model с corresponding dbt model.
- Merges contents.
- Updates models/_models.yml.
- Deletes semantic_models/*.yml (optional flag).
Время: автоматическое, 2-3 минуты на проект.
Option 3: Phased mixed (large project)
Если проект большой, делать all-at-once может быть risky. Phased:
Phase 1 (Week 1): Pilot 5 semantic_models. Convert. Test thoroughly.
Phase 2 (Week 2-3): Domain by domain (orders -> customers -> ...).
Phase 3 (Week 4): Verify nothing missed. Delete semantic_models/ directory.
V1 и v2 coexist во время transition — dbt parse обрабатывает оба.
Тонкости миграции
Issue 1: Naming difference
В v1: semantic_model имеет своё name (часто sm_orders или orders).
В v2: name = model name (fct_orders).
Если у вас были metrics, ссылающиеся на v1 names:
# v1
metrics:
- name: revenue
type: simple
type_params:
measure: order_amount
semantic_model: orders # v1 name
После миграции:
# v2 — semantic_model имя теперь fct_orders
metrics:
- name: revenue
type: simple
type_params:
measure: order_amount
semantic_model: fct_orders # renamed
Все references в metrics, saved_queries — нужно обновить. Autofix это делает.
Issue 2: Cross-references
Если semantic_model A reference semantic_model B (через entities), v2 не меняет — entities остаются те же. Только wrapper YAML структура другая.
Issue 3: Time spine
Time spine model description тоже идёт в v2 формате:
# v2
models:
- name: time_spine_daily
description: "Daily time spine"
semantic_model:
defaults:
agg_time_dimension: date_day
time_spine:
standard_granularity_column: date_day
dimensions:
- name: date_day
type: time
type_params:
time_granularity: day
V1 had similar, но в semantic_models: block отдельно.
Issue 4: Documentation
dbt docs generate показывает v2 spec correctly. Но если у вас custom docs site (built on top of manifest.json), нужно проверить, что parser обрабатывает nested semantic_model.
Compatibility timeline
dbt 1.6 (mid 2024): v1 spec introduced.
dbt 1.10 (2025): v1 spec stable. Adoption growing.
dbt 1.11 (Q4 2025): v2 spec preview (experimental).
dbt 1.12 (Apr 2026): v2 spec stable. Recommended for new projects.
dbt 1.13 (planning): v2 default. v1 still works (deprecation warning).
dbt 1.14+: v1 deprecated. Migration recommended.
dbt 1.16 (future): v1 removed. v2 only.
Timeline gives 2-3 years для migration. No need to rush. Но новые проекты — сразу v2.
Итого
- V2 YAML spec в dbt 1.12 — nested
semantic_model:подmodels[]. Single file для model + semantic. - Improvement над v1: no duplication, single source of truth, easier refactoring, better IDE support.
- Migration tools:
dbt-autofixавтоматически конвертирует. Manual путь для small projects. - Backward compatibility: dbt 1.12+ поддерживает оба spec. v1 deprecated, но не removed.
- Tricky migration issues: semantic_model name изменяется (теперь = model name), references в metrics/saved_queries нужно обновить.
- V2-only features: inherit descriptions, reference column tests, embedded saved_queries, materialized measure spans (experimental).
- Timeline: 1.12 — v2 stable, 1.13-1.14 — v2 default + v1 deprecation, 1.16+ — v1 removed (estimated 2-3 года).
- Strategic approach: new projects — v2 сразу; existing — phased migration через autofix + reference updates + consumer coordination.
Следующий урок — dbt Semantic Layer API: JDBC, GraphQL, Python SDK, MCP server для AI agents.