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

О переменной execute

execute — это переменная Jinja, которая возвращает True, когда dbt находится в режиме "execute".

Когда вы выполняете команду dbt compile или dbt run, dbt:

  1. Читает все файлы в вашем проекте и генерирует манифест, состоящий из моделей, тестов и других узлов графа, присутствующих в вашем проекте. В этом этапе dbt использует операторы ref и source, которые он находит, чтобы сгенерировать DAG для вашего проекта. На этом этапе SQL не выполняется, и execute == False.
  2. Компилирует (и выполняет) каждый узел (например, строит модели или запускает тесты). На этом этапе SQL выполняется, и execute == True.

Любая Jinja, которая полагается на результат, возвращаемый из базы данных, вызовет ошибку на этапе разбора. Например, этот SQL вызовет ошибку:

models/order_payment_methods.sql
1   {% set payment_method_query %}
2 select distinct
3 payment_method
4 from {{ ref('raw_payments') }}
5 order by 1
6 {% endset %}
7
8 {% set results = run_query(payment_method_query) %}
9
10 {# Возвращает первый столбец #}
11 {% set payment_methods = results.columns[0].values() %}

Ошибка, возвращаемая dbt, будет выглядеть следующим образом:

Encountered an error:
Compilation Error in model order_payment_methods (models/order_payment_methods.sql)
'None' has no attribute 'table'

Это происходит потому, что строка №11 в предыдущем примере кода ({% set payment_methods = results.columns[0].values() %}) предполагает, что был возвращен table, тогда как на этапе разбора этот запрос не был выполнен.

Чтобы обойти это, оберните любую проблемную Jinja в оператор {% if execute %}:

models/order_payment_methods.sql
{% set payment_method_query %}
select distinct
payment_method
from {{ ref('raw_payments') }}
order by 1
{% endset %}

{% set results = run_query(payment_method_query) %}
{% if execute %}
{# Возвращает первый столбец #}
{% set payment_methods = results.columns[0].values() %}
{% else %}
{% set payment_methods = [] %}
{% endif %}

Парсинг и выполнение

Парсинг (parsing) в Jinja — это этап, на котором dbt:

  • Читает файлы вашего проекта.
  • Находит вызовы ref и source.
  • Находит определения макросов.
  • Строит граф зависимостей (DAG).

На этом этапе dbt не выполняет никакой SQLexecute == False.

Выполнение (execution) — это этап, когда dbt действительно выполняет SQL и строит модели — execute == True.

Во время выполнения dbt:

  • Рендерит полные Jinja-шаблоны в SQL.
  • Разрешает все вызовы ref() и source() в соответствующие имена таблиц или представлений.
  • Выполняет SQL из ваших моделей при выполнении таких команд, как dbt run, dbt test, dbt seed или dbt snapshot.
  • Создаёт или обновляет таблицы/представления в хранилище данных.
  • Применяет материализации (incremental, table, view, ephemeral).

Флаг execute влияет на значения, возвращаемые ref() и source(), и не будет работать так, как ожидается, внутри sql_header.

Причина в том, что при первоначальном парсинге проекта dbt находит все использования ref() и source() для построения DAG, но не разрешает их в реальные идентификаторы базы данных. Вместо этого dbt подставляет временные значения-заглушки, чтобы SQL корректно компилировался на этапе парсинга.

Примеры

Макросы вроде log() и exceptions.warn() всё равно вычисляются на этапе парсинга, во время «первого прохода» рендера Jinja, который dbt использует для извлечения ref, source и config. В результате dbt также выполняет любой логгинг или вывод предупреждений уже на этом этапе.

Несмотря на то, что фактическое выполнение ещё не происходит, dbt всё равно выводит эти лог-сообщения во время парсинга. Это может сбивать с толку — выглядит так, будто dbt что-то реально делает, хотя на самом деле он лишь парсит проект.

$ dbt run
15:42:01 Running with dbt=1.10.2
15:42:01 I'm running a query now. <------ это вводит в заблуждение!!!! на самом деле запрос не выполняется
15:42:01 Found 1 model, 0 tests, 0 snapshots, 0 macros, 0 operations, 0 seed files, 0 sources, 0 exposures, 0 metrics
15:42:01
15:42:01 Concurrency: 8 threads (target='dev')
15:42:01
15:42:01 1 of 1 START table model analytics.my_model .................................. [RUN]
15:42:01 I'm running a query now
15:42:02 1 of 1 OK created table model analytics.my_model ............................. [OK in 0.36s]

Логирование полностью квалифицированных имён отношений

Предположим, у вас есть отношение relation, полученное, например, так: {% set relation = ref('my_model') %} или {% set relation = source('source_name', 'table_name') %}. Это может привести к неожиданному или запутывающему поведению на этапе парсинга:


{%- if load_relation(relation) is none -%}
{{ log("Relation is missing: " ~ relation, True) }}
{% endif %}

Чтобы избежать этого, добавьте проверку флага execute, чтобы код выполнялся только тогда, когда dbt действительно выполняет модели, а не просто подготавливает их.

Используйте команду do exceptions.warn, чтобы вывести предупреждение во время выполнения модели, не прерывая запуск.


{%- if execute and load_relation(relation) is none -%}
{% do exceptions.warn("Relation is missing: " ~ relation) %}
{{ log("Relation is missing: " ~ relation, info=True) }}
{%- endif -%}


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

0
Loading