Перейти к основному содержимому

О функции ref

select * from {{ ref("node_name") }}

Определение

Эта функция:

  • Возвращает объект Relation для модели, сида или снапшота
  • Создаёт зависимости между узлом, на который идёт ссылка, и текущей моделью, что полезно для документации и выбора узлов
  • При компиляции разворачивается в полное имя объекта в базе данных

Самая важная функция в dbt — это ref(); невозможно построить даже умеренно сложные модели без нее. ref() — это способ ссылаться на одну модель внутри другой. Это очень распространенное поведение, так как обычно модели строятся так, чтобы "накладываться" друг на друга. Вот как это выглядит на практике:

model_a.sql
select *
from public.raw_data
model_b.sql
select *
from {{ref('model_a')}}

ref() на самом деле выполняет две важные задачи. Во-первых, она интерполирует схему в ваш файл модели, чтобы вы могли изменить схему развертывания через конфигурацию. Во-вторых, она использует эти ссылки между моделями для автоматического построения графа зависимостей. Это позволит dbt развертывать модели в правильном порядке при использовании dbt run.

Функция {{ ref }} возвращает объект Relation, который имеет те же атрибуты table, schema и name, что и {{ this }} variable.

Продвинутое использование ref

Версионированный ref

Функция ref поддерживает необязательный аргумент - version (или v). Когда аргумент версии предоставляется функции ref, dbt возвращает объект Relation, соответствующий указанной версии ссылочной модели.

Эта функциональность полезна при ссылке на версионированные модели, которые вносят критические изменения, создавая новые версии, но гарантирует отсутствие критических изменений в существующих версиях модели.

Если аргумент version не предоставлен для ref версионированной модели, используется последняя версия. Это имеет преимущество автоматического включения последних изменений ссылочной модели, но существует риск включения критических изменений.

Пример

models/<schema>.yml

models:
- name: model_name
latest_version: 2
versions:
- v: 2
- v: 1
 -- возвращает объект `Relation`, соответствующий версии 1 model_name
select * from {{ ref('model_name', version=1) }}
 -- возвращает объект `Relation`, соответствующий версии 2 (последней версии) model_name
select * from {{ ref('model_name') }}

Ссылка на модели из конкретных проектов

Вы также можете ссылаться на модели из других проектов, используя вариант функции ref с двумя аргументами. Указывая и пространство имён (это может быть проект или пакет), и имя модели, вы обеспечиваете однозначность и избегаете любой неоднозначности при использовании ref. Это особенно полезно при работе с моделями из разных проектов или пакетов.

При использовании двух аргументов с проектами (но не с пакетами) также необходимо настроить межпроектные зависимости.

Следующий синтаксис демонстрирует, как ссылаться на модель из конкретного проекта или пакета:

select * from {{ ref('project_or_package', 'model_name') }}

Мы рекомендуем использовать двухаргументный ref всякий раз, когда вы ссылаетесь на модель, определенную в другом пакете или проекте. Хотя это не требуется во всех случаях, это более явно для вас, для dbt и будущих читателей вашего кода.

Мы особенно рекомендуем использовать двухаргументный ref, чтобы избежать двусмысленности в случаях, когда имя модели дублируется в нескольких проектах или установленных пакетах. Если вы используете одноаргументный ref (только model_name), dbt будет искать модель с таким именем в том же пространстве имен (пакет или проект); если он не найдет ни одной, он выдаст ошибку.

Примечание: project_or_package должно совпадать с name проекта/пакета, как определено в его dbt_project.yml. Это может отличаться от имени репозитория. Оно никогда не включает имя организации репозитория. Например, если вы используете пакет fivetran/stripe, имя пакета — stripe, а не fivetran/stripe.

Принудительное задание зависимостей

При обычном использовании dbt знает правильный порядок запуска всех моделей на основе использования функции ref, поскольку он обнаруживает их все на этапе парсинга. dbt выбросит ошибку, если во время выполнения обнаружит «неожиданный» ref (то есть такой, который был скрыт на этапе парсинга). Самая распространённая причина этого — когда ref находится внутри ветки оператора if, которая не была вычислена во время парсинга.

conditional_ref.sql
--This macro already has its own `if execute` check, so this one is redundant and introduced solely to cause an error
{% if execute %}
{% set sql_statement %}
select max(created_at) from {{ ref('processed_orders') }}
{% endset %}

```sql
{%- set newest_processed_order = dbt_utils.get_single_value(sql_statement, default="'2020-01-01'") -%}
{% endif %}

select

*,
last_order_at > '{{ newest_processed_order }}' as has_unprocessed_order

from {{ ref('users') }}
  • В этом случае dbt не знает, что processed_orders является зависимостью, потому что во время парсинга значение execute равно false.
  • Чтобы решить эту проблему, используйте SQL‑комментарий вместе с функцией ref — dbt сможет корректно определить зависимость, и при этом скомпилированный запрос останется валидным:
conditional_ref.sql
-- Now that this ref is outside of the if block, it will be detected during parsing
-- depends_on: {{ ref('processed_orders') }}

{% if execute %}
{% set sql_statement %}
select max(created_at) from {{ ref('processed_orders') }}
{% endset %}

{%- set newest_processed_order = dbt_utils.get_single_value(sql_statement, default="'2020-01-01'") -%}
{% endif %}

select

*,
last_order_at > '{{ newest_processed_order }}' as has_unprocessed_order

from {{ ref('users') }}
подсказка

Чтобы dbt корректно распознал зависимость, используйте SQL‑комментарий, а не комментарий Jinja. Комментарии Jinja ({# ... #}) не работают и игнорируются парсером dbt — в результате ref никогда не обрабатывается и не разрешается. SQL‑комментарии же (-- или `/* ... */) работают, потому что dbt продолжает вычислять Jinja‑выражения даже внутри SQL‑комментариев.

Нашли ошибку?

0
Loading