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

Как мы сократили количество тестов на 80%, повысив качество данных: сила агрегации сбоев тестов в dbt

· 7 мин. чтения
Noah Kennedy

Тестирование качества данных в вашем хранилище — важный аспект любой зрелой конвейерной обработки данных. Одним из самых больших препятствий для разработки успешного конвейера качества данных является агрегация сбоев и успехов тестов в информативной и действенной форме. Однако обеспечение действенности может быть сложной задачей. Если игнорировать, сбои тестов могут засорить конвейер и создать неэффективный шум, делая вашу инфраструктуру тестирования неэффективной.

Создание структуры качества данных, которая позволяет заинтересованным сторонам принимать меры по устранению сбоев тестов, является сложной задачей. Без действенной структуры тесты на качество данных могут обернуться против вас — один провалившийся тест превращается в два, затем в десять, и внезапно у вас слишком много сбоев тестов, чтобы действовать по ним.

Недавно мы полностью пересмотрели нашу тестовую структуру. Мы сократили количество тестов на 80%, чтобы создать более зрелую структуру, включающую метаданные и подчеркивающую действенность. Наша система управления качеством данных состоит из трех этапов, описанных ниже:

  1. Использование контекстуальных знаний заинтересованных сторон, написание конкретных, высококачественных тестов данных, распространение результатов сбоев тестов в алиасные модели для легкого доступа.
  2. Агрегация результатов сбоев тестов с использованием макросов Jinja и предварительно настроенных метаданных для создания сводных таблиц высокого уровня.
  3. Создание представлений на основе базовой таблицы для разделения тестов по владельцу или серьезности и создание визуализаций с использованием нашего инструмента выбора.

Следует отметить, что эта структура предназначена для dbt v1.0+ на BigQuery. Небольшие адаптации, вероятно, необходимы для запуска этой структуры в другой среде.

Конкретные, высококачественные тесты данных

Когда мы говорим о высококачественных тестах данных, мы имеем в виду не только высококачественный код, но и информационное качество нашей тестовой структуры и соответствующих сообщений об ошибках. Изначально мы предполагали, что любой тест, по которому нельзя принять меры, не должен быть реализован. Позже мы поняли, что есть время и место для тестов, которые должны получать внимание при критической массе сбоев. Все, что нам нужно, это система с более высокой степенью специфичности: тесты должны иметь явную оценку серьезности, чтобы отфильтровать шум от общих, но незначительных сбоев. Каждый тест также должен соответствовать установленным RACI руководствам, которые определяют, какие группы решают какие сбои и что составляет критическую массу.

Чтобы гарантировать, что тесты всегда будут выполняться, мы реализуем тесты по-разному в зависимости от групп пользователей, которые должны действовать, когда тест проваливается. Это привело к тому, что у нас появилось два основных класса тестов — Тесты Целостности Данных (называемые Generic Tests в документации dbt) и Контекстно-Зависимые Тесты (называемые Singular Tests в документации dbt), с различными уровнями серьезности в обоих классах тестов.

Тесты Целостности Данных (Generic Tests) просты — это тесты, подобные проверке уникальности или ограничению not null. Эти тесты обычно могут быть выполнены командой платформы данных, а не экспертами в предметной области. Мы определяем Тесты Целостности Данных в наших YAML-файлах, аналогично тому, как они описаны в документации dbt по общим тестам. Они выглядят примерно так —

version: 2
models:
- name: customer
columns:
- name: id
description: Unique ID associated with the record
tests:
- unique:
alias: id__unique
- not_null:
alias: id__not_null
Пример Тестов Целостности Данных в YAML-файле — аргумент alias является важной частью, о которой будет сказано позже.

Контекстно-Зависимые Тесты более сложны и больше похожи на модели. По сути, это модели данных, которые выбирают плохие данные или записи, которые мы не хотим, определенные как SQL-файлы, которые находятся в каталоге dbt/tests. Пример показан ниже —

{{ config(
tags=['check_purchase_date_in_range', 'customer'],
alias='ad_hoc__check_purchase_date_in_range
)
}}

SELECT
id,
purchase_date
FROM
{{ ref('customer') }}
WHERE purchase_date < '1900-01-01'
Вышеприведенный тест выбирает всех клиентов, которые совершили покупку до 1900 года. Идея заключается в том, что любой клиент, существующий до 1900 года, вероятно, нереален.

Важно, что мы используем Алиас Теста, чтобы гарантировать, что все наши тесты следуют стандартной и предсказуемой схеме именования; наша схема именования для Тестов Целостности Данных — table_name_ _column_name__test_name, а для Контекстно-Зависимых Тестов — ad_hoc__test_name. Наконец, чтобы гарантировать, что все наши тесты могут быть агрегированы, мы модифицируем файл dbt_project.yml и устанавливаем тег store_failures в ‘TRUE’, таким образом сохраняя сбои тестов в SQL-таблицах.

На этом этапе разработки у нас есть Тесты Целостности Данных, определенные в YAML, и Контекстно-Зависимые Тесты, определенные как SQL-файлы. Тесты конкретны, действенны и реалистичны, и каждый из них сопровождается идеей о серьезности и группой пользователей, которым важно, когда он проваливается. Все наши тесты имеют алиасы в соответствии с определенной схемой именования, чтобы мы знали, в какие таблицы они будут помещать данные, и мы модифицировали конфигурацию нашего проекта dbt, чтобы установить store_failures в true для всех тестов.

Агрегация тестов с использованием метаданных

Наш следующий шаг — определить метаданные тестов для каждого из наших тестов. Причина этого двояка. Во-первых, мы хотим убедиться, что на последующих этапах визуализации мы можем прикрепить описание и более читаемое имя к тесту. Во-вторых, наличие файла метаданных позволяет нам прикрепить к тестам всевозможную дополнительную информацию: кто владеет тестом, насколько он серьезен, и активен ли тест или неактивен, чтобы назвать несколько.

Наши метаданные хранятся в файле семян. Единственное обязательное поле здесь — test_alias, которое действует как для связывания метаданных с именем таблицы сбоев тестов. Мы также включаем серьезность теста, владельца теста, описание теста и несколько других полей, которые действуют как фильтры для будущих агрегированных таблиц.

После определения нашего файла метаданных Seed мы начинаем процесс агрегации наших данных. Мы агрегируем наши данные, определяя базовую модель, которая объединяет результаты сбоев тестов (теперь хранящиеся в отдельной схеме) с определенными нами метаданными. Ниже приведен пример того, как выглядит этот код —

{{ config(
materialized = 'incremental',
partition_by = {'field': 'load_date', 'data_type': 'date'},
incremental_strategy = 'merge',
unique_key='row_key',
full_refresh=false,
tags=['dq_test_warning_failures','customer_mart', 'data_health']
)
}}

WITH failures as (
SELECT
count(*) as test_failures,
_TABLE_SUFFIX as table_suffix,
FROM {{ var('customer_mart_schema') }}_dbt_test__audit.`*`
GROUP BY _TABLE_SUFFIX
),

metadata as (
SELECT
test_owner,
test_alias,
test_description,
split(test_alias, '__')[SAFE_ORDINAL(2)] as test_name,
test_severity
FROM {{ref('test_warning_metadata')}}
),

SELECT
m.*,
f.*
FROM metadata m
LEFT JOIN failures f on m.test_alias = f.table_suffix
WHERE m.is_active is TRUE
Пример Базовой Модели Агрегации Метаданных + Сбоев Тестов.

Некоторые ключевые компоненты:

  • Мы материализуем нашу базовую модель как инкрементальную, устанавливаем full_refresh в false в dbt_project.yml и разделяем нашу таблицу по дате, чтобы гарантировать сохранение исторических данных.
  • Мы используем BigQuery, который позволяет выборку с помощью подстановочных знаков и значительно упрощает нашу жизнь. Если вы используете другую платформу, вам, скорее всего, нужно будет написать цикл с использованием Jinja.
  • Поскольку у нас есть ожидаемая схема именования, мы можем разделить test_alias, чтобы получить такие компоненты, как имя таблицы или имя столбца, если это необходимо.

Теперь, когда наша базовая модель разработана, у нас есть центральная точка истины, которая агрегирует все наши тесты данных в одном месте, с метаданными, которые дают больше информации о тесте, а также о том, кто им владеет. Наш последний шаг — использование нашей базовой таблицы для получения дополнительных сведений из наших тестов.

Завершающие штрихи и выводы

С нашей окончательной базовой таблицей качества данных существует множество других вариантов для очистки нашей структуры или создания визуализаций. Наша команда использует базовую таблицу несколькими основными способами.

Во-первых, мы создаем представления на основе базовой таблицы, которые фильтруются по владельцу теста. Мы твердо верим, что шум тестов является самым большим риском для успеха качественной структуры. Создание конкретных представлений похоже на предоставление каждой команде увеличительного стекла, которое позволяет им увеличивать только те тесты, которые их интересуют. У нас также есть панель управления, в настоящее время в Google Looker Studio, которая показывает исторические сбои тестов с набором фильтров, позволяющих пользователям увеличивать тесты с высокой серьезностью и создавать машинно-составленные примерные запросы для пользователей, чтобы выбрать провалившиеся записи. Когда тест проваливается, бизнес-аналитик может скопировать и вставить запрос с панели управления и получить всю соответствующую информацию.

Как и в любой структуре, это всегда работа в процессе — мы все еще сталкиваемся с проблемами шума в наших тестах и все еще боремся с тем, чтобы наши пользователи заботились о сбоях тестов. Однако мы обнаружили, что эта структура данных работает исключительно хорошо, позволяя пользователям данных создавать и развертывать свои собственные тесты. Все, что им нужно сделать, это отправить pull-запрос с SQL-кодом, который отмечает плохие данные, и написать одну строку метаданных.

Comments

Loading