Сбои модульных тестов DBT со сложными структурами: Полное руководство
Узнайте, как исправлять сбои модульных тестов DBT при работе со сложными структурами в Databricks. Полные решения, включая изменения конфигурации, структурные обходные пути и лучшие практики для обработки больших структур данных в вашем конвейере данных.
Юнит-тесты DBT не проходят, когда структура имеет слишком много полей
Я запускаю модели DBT на Databricks и реализую для них юнит-тесты. Мои юнит-тесты не проходят, когда таблицы содержат структуры с большим количеством полей.
Описание проблемы
Когда я запускаю свои юнит-тесты DBT, я сталкиваюсь со следующей ошибкой:
Runtime Error in unit_test test_my_model (tests/unit/test_path/test_my_model.yml)
An error occurred during execution of unit test 'test_my_model'. There may be an error in the unit test definition: check the data types.
Database Error
[PARSE_SYNTAX_ERROR] Syntax error at or near '.'. SQLSTATE: 42601
== SQL ==
/* {"app": "dbt", "dbt_version": "1.9.4", "dbt_databricks_version": "1.10.2", "databricks_sql_connector_version": "4.0.3"} */
create or replace temporary view `test_my_model__dbt_tmp` as
select * from (
with
__dbt__cte__table_1 as (
-- Fixture for table_1
select
cast(null as bigint) as field_1,
cast(null as timestamp) as field_2,
cast(null as array<struct<sub_field_1:boolean,sub_field_2:boolean,[20 more sub-fields...],... 108 more fields>>) as field_3,
--------------------------------------------------------------------------------------------^^^
[more fields...]
Проблема заключается в том, что DBT обрезает представление схемы при отправке в Databricks, конкретно показывая “… 108 more fields”, что вызывает синтаксическую ошибку.
Пример юнит-теста
Вот пример моего юнит-теста DBT:
unit_tests:
- name: test_my_model
model: my_model
given:
- input: source('my_schema', 'my_table_1')
rows:
- {application_id: 1, created_at: "2025-01-01"}
- {application_id: 2, created_at: "2025-01-03"}
- input: ref('reference__reference__days')
rows:
- {date: "2025-01-01"}
- {date: "2025-01-02"}
- {date: "2025-01-03"}
- input: source('my_schema', 'my_table_2')
rows:
- {id: 10, application_id: 1, effective_on: "2025-01-01"}
- {id: 11, application_id: 1, effective_on: "2025-01-02"}
- {id: 20, application_id: 2, effective_on: "2025-01-03"}
- {id: 21, application_id: 2, effective_on: "2025-01-03"}
expect:
rows:
- {application_id: 1, date: "2025-01-01", effective_on: "2025-01-01"}
- {application_id: 1, date: "2025-01-02", effective_on: "2025-01-02"}
- {application_id: 1, date: "2025-01-03", effective_on: "2025-01-02"}
- {application_id: 2, date: "2025-01-03", effective_on: "2025-01-03"}
Вопрос
Существует ли способ избежать этой проблемы с юнит-тестами DBT при работе со структурами, имеющими много полей? Конкретно, могу ли я либо:
- Заставить DBT отправлять полную схему без её обрезки
- Настроить DBT на отправку только необходимых полей в структурах, а не всех полей
Этот вопрос актуален для пользователей DBT, работающих со сложными структурами данных на Databricks, которым необходимо реализовывать комплексные юнит-тесты.
Тесты единиц измерения DBT не проходят, когда структуры имеют слишком много полей из-за команды Databricks DESCRIBE EXTENDED, которая обрезает информацию о сложных типах данных, вызывая синтаксические ошибки в генерируемом SQL. Эта проблема в основном затрагивает версии dbt-databricks v1.11 и старше, но может быть решена путем настройки флага use_info_schema_for_columns в значение True или реализации структурных обходных решений для сложных типов данных.
Содержание
- Анализ корневой причины
- Немедленные решения
- Структурные обходные решения
- Лучшие практики для сложных структур
- Расширенные параметры конфигурации
- Альтернативные методы тестирования
Анализ корневой причины
Основная проблема заключается в том, как Databricks обрабатывает сложные типы данных, такие как структуры с множеством полей. Когда DBT генерирует тесты единиц измерения, ему необходимо понимать схему таблиц для создания правильных тестовых фикстур. Проблема возникает потому, что:
Проблема усечения в Databricks: Команда DESCRIBE EXTENDED, которую DBT использует по умолчанию для получения метаданных столбцов, обрезает информацию при работе со сложными структурами типов. Как показано в сообщении об ошибке, DBT генерирует SQL с усеченными представлениями, такими как “… еще 108 полей”, что вызывает ошибки синтаксического анализа.
Согласно документации dbt-databricks, “describe extended обрезает информацию, когда тип является сложной структурой” - это и есть корневая причина ваших сбоев тестов единиц измерения.
Зависимость от версии: Эта проблема в основном затрагивает версии dbt-databricks v1.11 и старше. В версиях 1.9 и 1.10 флаг use_info_schema_for_columns по умолчанию имел значение False, что заставляло DBT использовать проблемный подход DESCRIBE EXTENDED.
Ограничения полей структуры: Как указано в официальной документации по тестам единиц измерения DBT, “Вы не можете использовать только подмножество полей в STRUCT” - это ограничение усугубляет проблему усечения при работе с большими структурами.
Немедленные решения
Настройка использования Information Schema
Наиболее прямое решение - включить флаг use_info_schema_for_columns в конфигурации вашего проекта DBT:
# dbt_project.yml
config-version: 2
# Настройка адаптера Databricks для использования information_schema вместо describe extended
vars:
use_info_schema_for_columns: true
Это указывает DBT запрашивать таблицы information_schema вместо использования DESCRIBE EXTENDED, что полностью избегает проблемы усечения.
Почему это работает: information_schema предоставляет полные метаданные столбцов без усечения, позволяя DBT генерировать точные тестовые фикстуры даже для сложных структур с множеством полей.
Обновление адаптера Databricks
Если вы используете старую версию dbt-databricks, рассмотрите возможность обновления до последней версии:
# Обновление dbt-databricks
pip install --upgrade dbt-databricks
Более новые версии имеют улучшенную обработку сложных типов данных и могут включать исправления для этой конкретной проблемы.
Структурные обходные решения
Разделение сложных структур на несколько моделей
При работе с extremely большими структурами рассмотрите возможность разделения их на отдельные модели:
-- Исходная сложная модель
-- {{ config materialized='table' )}}
select
id,
user_info_struct, -- Содержит 100+ полей
event_data_struct -- Содержит 50+ полей
from source_table
-- Разделение на более простые модели
-- models/stg_user_info.sql
select id, user_info_struct from source_table
-- models/stg_event_data.sql
select id, event_data_struct from source_table
Этот подход позволяет тестировать более простые модели индивидуально, сохраняя исходную структуру через соединения.
Использование промежуточных моделей для тестов
Создайте промежуточные модели, которые упрощают или “расплющивают” сложные структуры для целей тестирования:
-- models/test_user_flattened.sql
select
id,
user_info_struct.name,
user_info_struct.email,
-- Включаем только поля, необходимые для теста
user_info_struct.status
from {{ ref('stg_user_info') }}
Ваши тесты единиц измерения затем могут ссылаться на эти расплющенные модели вместо работы с полной сложной структурой.
Подход архитектуры медальона
Примите рекомендуемую Databricks архитектуру медальона:
# Бронзовый слой - сырые данные с полными структурами
- name: bronze_layer
materialized: table
# Серебряный слой - упрощенные структуры для обработки
- name: silver_layer
materialized: table
# Золотой слой - финальные аналитические модели
- name: gold_layer
materialized: table
Этот подход естественно разбивает сложные структуры данных на управляемые компоненты.
Лучшие практики для сложных структур
Стратегия выбора полей
При написании тестов единиц измерения будьте стратегичны в выборе полей структуры:
unit_tests:
- name: test_simplified_model
model: simplified_model
given:
- input: source('complex_source')
rows:
# Включаем только существенные поля для теста
- {id: 1, user_struct: {name: "Алиса", status: "active"}}
- {id: 2, user_struct: {name: "Боб", status: "inactive"}}
Примечание: Как указано в документации DBT, “Тесты единиц измерения предназначены для проверки ожидаемых значений, а не типов данных самих по себе” - сосредоточьтесь на значениях, важных для вашего конкретного тестового случая.
Генерация тестовых данных
Создайте вспомогательные макросы для генерации тестовых структур данных:
{% macro generate_mock_struct() %}
cast(null as struct<
name: string,
email: string,
status: string,
created_at: timestamp,
-- Добавляем только поля, необходимые для вашего теста
updated_at: timestamp
>)
{% endmacro %}
Это помогает избежать проблемы усечения, включая только необходимые поля.
Изоляция тестовой среды
Изолируйте тестирование сложных структур в выделенные тестовые среды:
# dbt_project.yml
test-paths:
- "tests/unit/simple_structs"
- "tests/unit/complex_structs"
models:
+schema: "{{ target.schema }}"
+tags: ["production"]
Это позволяет применять разные стратегии тестирования в зависимости от сложности.
Расширенные параметры конфигурации
Пользовательский извлечение метаданных столбцов
Для сложных сценариев вы можете создать пользовательские макросы для переопределения стандартного извлечения метаданных столбцов:
{% macro get_columns_in_relation(relation) %}
{% set columns = [] %}
-- Используем пользовательскую логику для обработки сложных структур
{% if relation.type == 'VIEW' %}
{% for column in adapter.get_columns_in_relation(relation) %}
{% if column.data_type|lower starts with 'struct' %}
-- Обработка столбцов со сложными структурами
{% do columns.append(api.Column(column.name, column.data_type, column.dtype)) %}
{% else %}
-- Обработка обычных столбцов
{% do columns.append(column) %}
{% endif %}
{% endfor %}
{% else %}
-- Используем стандартное поведение для таблиц
{% set columns = adapter.get_columns_in_relation(relation) %}
{% endif %}
{{ return(columns) }}
{% endmacro %}
Пользовательская конфигурация тестов
Добавьте платформо-специфичные конфигурации тестов:
# dbt_project.yml
models:
databricks:
+materialized: table
# Настройка обработки сложных типов
+complex_struct_handling: "flatten"
+max_struct_fields: 50
unit_tests:
+complex_struct_mode: "selective"
Настройки, зависящие от среды
Настройте разные параметры для разных сред:
# profiles.yml
your_databricks:
target: dev
outputs:
dev:
type: databricks
host: your-databricks-workspace
http_path: sql/protocolv1/o/1234567890/1234-567890-abcdef123
token: your_token
# Включаем info schema для dev
use_info_schema_for_columns: true
prod:
type: databricks
host: your-databricks-workspace
http_path: sql/protocolv1/o/1234567890/1234-567890-abcdef123
token: your_token
# Используем стандартное для production
use_info_schema_for_columns: false
Альтернативные методы тестирования
Подход интеграционного тестирования
Когда тесты единиц измерения не работают из-за сложных структур, рассмотрите интеграционное тестирование:
# Сначала запускаем модели
dbt run --select my_model_with_complex_structs
# Затем тестируем нижестоящие модели
dbt test --select downstream_models
Этот подход тестирует фактическую функциональность вместо отдельных тестовых сценариев единиц измерения.
Тестирование качества данных
Сосредоточьтесь на тестировании качества данных вместо тестов единиц измерения для сложных структур:
# tests/data_quality.yml
version: 2
models:
- name: my_model_with_complex_structs
data_tests:
- unique:
column_name: id
- not_null:
column_name: id
- dbt_utils.expression_is_true:
expression: "struct_field_count(user_struct) <= 100"
Пользовательские тестовые макросы
Создайте пользовательские тестовые макросы специально для сложных структур:
{% macro test_struct_not_too_large(model, field, max_size) %}
{% set query %}
select count(*) as failures
from {{ model }}
where size({{ field }}) > {{ max_size }}
{% endset %}
{{ run_query(query) }}
{% endmacro %}
Это позволяет тестировать структурную сложность без генерации усеченного SQL.
Источники
- Изменения в поведении адаптера dbt-databricks - Официальная документация
- Документация по тестам единиц измерения - dbt Developer Hub
- Stack Overflow: Тесты единиц измерения DBT не проходят, когда структура имеет слишком много полей
- Платформо-специфичные типы данных - dbt Developer Hub
- Databricks усекает типы данных через DESCRIBE EXTENDED - GitHub issue
- О свойстве data tests - dbt Developer Hub
Заключение
Сбои тестов единиц измерения DBT с сложными структурами в Databricks могут быть эффективно управляемы с помощью нескольких подходов:
Немедленные действия: Включите флаг use_info_schema_for_columns в конфигурации DBT, чтобы избежать проблемы усечения, вызванной командой DESCRIBE EXTENDED.
Структурные решения: Рассмотрите возможность разделения сложных структур на несколько моделей или использования архитектуры медальона для упрощения обработки данных и тестирования.
Стратегическое тестирование: Сосредоточьтесь на существенных полях в тестах единиц измерения и создавайте пользовательские макросы для генерации тестовых данных, которые избегают проблем усечения.
Долгосрочная оптимизация: Обновитесь до последней версии dbt-databricks и реализуйте конфигурации, зависящие от среды, для соответствующей обработки разных уровней сложности.
Комбинируя эти подходы, вы можете поддерживать всестороннее покрытие тестирования, работая со сложными структурами данных в Databricks, обеспечивая как качество данных, так и эффективность разработки.