Использование dbt Cloud для создания аналитических и ML-готовых конвейеров с SQL и Python в Snowflake
Введение
Цель этого воркшопа — продемонстрировать, как можно использовать SQL и Python вместе в одном рабочем процессе для запуска аналитических и моделей машинного обучения в dbt Cloud.
Весь код сегодняшнего воркшопа можно найти на GitHub.
Что вы будете использовать во время лабораторной работы
Чему вы научитесь
- Как строить масштабируемые конвейеры преобразования данных с использованием dbt и Snowflake с помощью SQL и Python
- Как использовать копирование данных в Snowflake из публичного S3-бакета
Что вам нужно знать
- Базовые и средние знания SQL и Python.
- Базовое понимание основ dbt. Мы рекомендуем курс dbt Fundamentals, если вам интересно.
- Общий процесс машинного обучения (кодирование, обучение, тестирование)
- Простые алгоритмы ML — мы будем использовать логистическую регрессию, чтобы сосредоточиться на рабочем процессе, а не на алгоритмах!
Что вы создадите
- Набор аналитических и предсказательных конвейеров данных, используя да нные Формулы 1, с использованием dbt и Snowflake, применяя лучшие практики, такие как тесты качества данных и продвижение кода между средами
- Мы создадим инсайты для:
- Поиск среднего времени круга и скользящего среднего за годы (в целом оно увеличивается или уменьшается)?
- Какой конструктор имеет самые быстрые пит-стопы в 2021 году?
- Прогнозирование позиции каждого водителя, используя данные за десятилетие (2010 - 2020)
В качестве входных данных мы будем использовать наборы данных Формулы 1, размещенные в публичном S3-бакете dbt Labs. Мы создадим Snowflake Stage для наших CSV-файлов, а затем используем функцию Snowflake COPY INTO
, чтобы скопировать данные из наших CSV-файлов в таблицы. Данные Формулы 1 доступны на Kaggle. Данные изначально собраны из Ergast Developer API.
В целом, мы настроим среды, построим масштабируемые конвейеры в dbt, установим тесты данных и продвинем код в производство.
Настройка Snowflake
- Войдите в свой пробный аккаунт Snowflake. Вы можете зарегистрироваться для пробного аккаунта Snowflake, используя эту форму, если у вас его нет.
- Убедитесь, что ваш аккаунт настроен с использованием AWS в US East (N. Virginia). Мы будем копировать данные из публичного AWS S3-бакета, размещенного dbt Labs в регионе us-east-1. Убедившись, что наша настройка среды Snowflake соответствует региону нашего бакета, мы избегаем любых задержек при копировании и извлечении данных между регионами.
-
После создания вашего аккаунта и его подтверждения из письма для регистрации, Snowflake перенаправит вас обратно в интерфейс, называемый Snowsight.
-
Когда Snowsight впервые открывается, ваше окно должно выглядеть следующим образом, с вами, вошедшим в систему как ACCOUNTADMIN с открытыми демонстрационными листами:
- Перейдите в Admin > Billing & Terms. Нажмите Enable > Acknowledge & Continue, чтобы включить пакеты Anaconda Python для работы в Snowflake.
- Наконец, создайте новый лист, выбрав + Worksheet в правом верхнем углу.
Подключение к источнику данных
Нам нужно получить наш источник данных, скопировав наши данные Формулы 1 в таблицы Snowflake из публичного S3-бакета, который размещает dbt Labs.
-
Когда создается новый аккаунт Snowflake, в вашем аккаунте должен быть предварительно настроенный склад с именем
COMPUTE_WH
. -
Если по какой-либо причине в вашем аккаунте нет этого склада, мы можем создать склад, используя следующий скрипт:
create or replace warehouse COMPUTE_WH with warehouse_size=XSMALL
-
Переименуйте лист в
data setup script
, так как мы будем размещать код в этом листе для загрузки данных Формулы 1. Убедитесь, что вы все еще вошли в систему как ACCOUNTADMIN и выберите склад COMPUTE_WH. -
Скопируйте следующий код в основное тело листа Snowflake. Вы также можете найти этот скрипт настройки в папке
setup
в Git-репозитории. Скрипт длинный, так как он загружает все данные, которые нам понадобятся сегодня!-- create and define our formula1 database
create or replace database formula1;
use database formula1;
create or replace schema raw;
use schema raw;
-- define our file format for reading in the csvs
create or replace file format csvformat
type = csv
field_delimiter =','
field_optionally_enclosed_by = '"',
skip_header=1;
--
create or replace stage formula1_stage
file_format = csvformat
url = 's3://formula1-dbt-cloud-python-demo/formula1-kaggle-data/';
-- load in the 8 tables we need for our demo
-- we are first creating the table then copying our data in from s3
-- think of this as an empty container or shell that we are then filling
create or replace table formula1.raw.circuits (
CIRCUITID NUMBER(38,0),
CIRCUITREF VARCHAR(16777216),
NAME VARCHAR(16777216),
LOCATION VARCHAR(16777216),
COUNTRY VARCHAR(16777216),
LAT FLOAT,
LNG FLOAT,
ALT NUMBER(38,0),
URL VARCHAR(16777216)
);
-- copy our data from public s3 bucket into our tables
copy into circuits
from @formula1_stage/circuits.csv
on_error='continue';
create or replace table formula1.raw.constructors (
CONSTRUCTORID NUMBER(38,0),
CONSTRUCTORREF VARCHAR(16777216),
NAME VARCHAR(16777216),
NATIONALITY VARCHAR(16777216),
URL VARCHAR(16777216)
);
copy into constructors
from @formula1_stage/constructors.csv
on_error='continue';
create or replace table formula1.raw.drivers (
DRIVERID NUMBER(38,0),
DRIVERREF VARCHAR(16777216),
NUMBER VARCHAR(16777216),
CODE VARCHAR(16777216),
FORENAME VARCHAR(16777216),
SURNAME VARCHAR(16777216),
DOB DATE,
NATIONALITY VARCHAR(16777216),
URL VARCHAR(16777216)
);
copy into drivers
from @formula1_stage/drivers.csv
on_error='continue';
create or replace table formula1.raw.lap_times (
RACEID NUMBER(38,0),
DRIVERID NUMBER(38,0),
LAP NUMBER(38,0),
POSITION FLOAT,
TIME VARCHAR(16777216),
MILLISECONDS NUMBER(38,0)
);
copy into lap_times
from @formula1_stage/lap_times.csv
on_error='continue';
create or replace table formula1.raw.pit_stops (
RACEID NUMBER(38,0),
DRIVERID NUMBER(38,0),
STOP NUMBER(38,0),
LAP NUMBER(38,0),
TIME VARCHAR(16777216),
DURATION VARCHAR(16777216),
MILLISECONDS NUMBER(38,0)
);
copy into pit_stops
from @formula1_stage/pit_stops.csv
on_error='continue';
create or replace table formula1.raw.races (
RACEID NUMBER(38,0),
YEAR NUMBER(38,0),
ROUND NUMBER(38,0),
CIRCUITID NUMBER(38,0),
NAME VARCHAR(16777216),
DATE DATE,
TIME VARCHAR(16777216),
URL VARCHAR(16777216),
FP1_DATE VARCHAR(16777216),
FP1_TIME VARCHAR(16777216),
FP2_DATE VARCHAR(16777216),
FP2_TIME VARCHAR(16777216),
FP3_DATE VARCHAR(16777216),
FP3_TIME VARCHAR(16777216),
QUALI_DATE VARCHAR(16777216),
QUALI_TIME VARCHAR(16777216),
SPRINT_DATE VARCHAR(16777216),
SPRINT_TIME VARCHAR(16777216)
);
copy into races
from @formula1_stage/races.csv
on_error='continue';
create or replace table formula1.raw.results (
RESULTID NUMBER(38,0),
RACEID NUMBER(38,0),
DRIVERID NUMBER(38,0),
CONSTRUCTORID NUMBER(38,0),
NUMBER NUMBER(38,0),
GRID NUMBER(38,0),
POSITION FLOAT,
POSITIONTEXT VARCHAR(16777216),
POSITIONORDER NUMBER(38,0),
POINTS NUMBER(38,0),
LAPS NUMBER(38,0),
TIME VARCHAR(16777216),
MILLISECONDS NUMBER(38,0),
FASTESTLAP NUMBER(38,0),
RANK NUMBER(38,0),
FASTESTLAPTIME VARCHAR(16777216),
FASTESTLAPSPEED FLOAT,
STATUSID NUMBER(38,0)
);
copy into results
from @formula1_stage/results.csv
on_error='continue';
create or replace table formula1.raw.status (
STATUSID NUMBER(38,0),
STATUS VARCHAR(16777216)
);
copy into status
from @formula1_stage/status.csv
on_error='continue'; -
Убедитесь, что все команды выбраны перед выполнением запроса — простой способ сделать это — использовать Ctrl-a, чтобы выделить весь код в листе. Выберите run (синий треугольник). Обратите внимание, как точка рядом с вашим COMPUTE_WH меняется с серого на зеленый, когда вы выполняете запрос. Таблица status является последней из всех 8 загруженных таблиц.
-
Давайте разберем этот довольно длинный запрос на составные части. Мы выполнили этот запрос, чтобы загрузить наши 8 таблиц Формулы 1 из публичного S3-бакета. Для этого мы:
- Создали новую базу данных с именем
formula1
и схему с именемraw
, чтобы разместить наши необработанные (непреобразованные) данные. - Определили формат файла для наших CSV-файлов. Важно, что здесь мы используем параметр
field_optionally_enclosed_by =
, так как строковые столбцы в наших CSV-файлах Формулы 1 используют кавычки. Кавычки используются вокруг строковых значений, чтобы избежать проблем с разбором, когда запятые,
и новые строки/n
в значениях данных могут вызвать ошибки загрузки данных. - Создали stage для размещения наших данных, которые мы собираемся загрузить. Snowflake Stages — это места, где хранятся файлы данных. Stages используются как для загрузки, так и для выгрузки данных в и из местоположений Snowflake. Здесь мы используем внешний stage, ссылаясь на S3-бакет.
- Создали наши таблицы для копирования данных. Это пустые таблицы с именем столбца и типом данных. Подумайте об этом как о создании пустого контейнера, который затем будет заполнен данными.
- Использовали оператор
copy into
для каждой из наших таблиц. Мы ссылаемся на наше staged местоположение, которое мы создали, и при ошибках загрузки продолжаем загружать остальные данные. У вас не должно быть ошибок загрузки данных, но если они возникнут, эти строки будут пропущены, и Snowflake сообщит вам, какие строки вызвали ошибки.
- Создали новую базу данных с именем
-
Теперь давайте посмотрим на некоторые из наших крутых данных Формулы 1, которые мы только что загрузили!
-
Создайте новый лист, выбрав + затем New Worksheet.
-
Перейдите в Database > Formula1 > RAW > Tables.
-
Запросите данные, используя следующий код. В таблице circuits всего 76 строк, поэтому нам не нужно беспокоиться об ограничении количества запрашиваемых данных.
select * from formula1.raw.circuits
-
Выполните запрос. С этого момента мы будем использовать сочетания клавиш Command-Enter или Control-Enter для выполнения запросов и не будем явно указывать этот шаг.
-
Просмотрите результаты запроса, вы должны увидеть информацию о трассах Формулы 1, начиная с Альберт-Парка в Австралии!
-
Наконец, убедитесь, что у вас есть все 8 таблиц, начиная с
CIRCUITS
и заканчиваяSTATUS
. Теперь мы готовы подключиться к dbt Cloud!
-
Настройка dbt Cloud
-
Мы будем использовать Snowflake Partner Connect для настройки аккаунта dbt Cloud. Использование этого метода позволит вам развернуть полноценный аккаунт dbt с вашим подключением Snowflake, управляемым репозиторием, средами и учетными данными, уже установленными.
-
Выйдите из своего листа, выбрав home.
-
В Snowsight убедитесь, что вы используете роль ACCOUNTADMIN.
-
Перейдите в Data Products > Partner Connect. Найдите dbt, используя строку поиска или перейдя в Data Integration. Выберите плитку dbt.
-
Теперь вы должны увидеть новое окно с надписью Connect to dbt. Выберите Optional Grant и добавьте базу данных
FORMULA1
. Это предоставит доступ вашей новой роли пользователя dbt к базе данных FORMULA1. -
Убедитесь, что
FORMULA1
присутствует в вашем optional grant перед нажатием Connect. Это создаст выделенного пользователя dbt, базу данных, склад и роль для вашей пробной версии dbt Cloud. -
Когда вы увидите окно Your partner account has been created, нажмите Activate.
-
Вы должны быть перенаправлены на страницу регистрации dbt Cloud. Заполните форму. Обязательно сохраните пароль где-нибудь для входа в будущем.
-
Выберите Complete Registration. Теперь вы должны быть перенаправлены на ваш аккаунт dbt Cloud, с подключением к вашему аккаунту Snowflake, развертыванием и средой разработки, а также примером задания.
-
Чтобы помочь вам с управлением версиями вашего проекта dbt, мы подключили его к управляемому репозиторию, что означает, что dbt Labs будет размещать ваш репозиторий для вас. Это даст вам доступ к рабочему процессу Git без необходимости создавать и размещать репозиторий самостоятельно. Вам не нужно будет знать Git для этого воркшопа; dbt Cloud поможет вам пройти через рабочий процесс. В будущем, когда вы будете разрабатывать свой собственный проект, не стесняйтесь использовать свой собственный репозиторий. Это позволит вам узнать больше о таких функциях, как Slim CI сборки после этого воркшопа.
Изменение имени схемы разработки и навигация по IDE
-
Сначала мы изменим имя нашей схемы по умолчанию, в которой будут строиться наши модели dbt. По умолчанию имя —
dbt_
. Мы изменим его наdbt_<ВАШЕ_ИМЯ>
, чтобы создать вашу личную схему разработки. Для этого нажмите на свое имя аккаунта в левом меню и выберите Account settings. -
Перейдите в меню Credentials и выберите Partner Connect Trial, чтобы развернуть меню учетных данных.
-
Нажмите Edit и измените имя вашей схемы с
dbt_
наdbt_YOUR_NAME
, заменивYOUR_NAME
вашими инициалами и именем (hwatson
используется в скриншотах лаборатории). Обязательно нажмите Save для сохранения изменений! -
Теперь у нас есть наша личная схема разработки, удивительно! Когда мы запустим наши первые модели dbt, они будут построены в этой схеме.
-
Давайте откроем интегрированную среду разработки (IDE) dbt Cloud и ознакомимся с ней. Выберите Develop в верхней части интерфейса.
-
Когда IDE загрузится, нажмите Initialize dbt project. Процесс инициализации создает набор файлов и папок, необ ходимых для запуска вашего проекта dbt.
-
После завершения инициализации вы можете просмотреть файлы и папки в меню дерева файлов. По мере продвижения по воркшопу мы обязательно коснемся нескольких ключевых файлов и папок, с которыми мы будем работать для создания нашего проекта.
-
Далее нажмите Commit and push, чтобы зафиксировать новые файлы и папки из шага инициализации. Мы всегда хотим, чтобы наши сообщения о фиксации были актуальны для работы, которую мы фиксируем, поэтому обязательно предоставьте сообщение, например,
initialize project
, и выберите Commit Changes. -
Фиксация вашей работы здесь сохранит ее в управляемом git-репозитории, который был создан во время регистрации Partner Connect. Эта начальная фиксация будет единственной фиксацией, которая будет сделана непосредственно в нашей ветке
main
, и с этого момента мы будем выполнять всю нашу работу в ветке разработки. Это позволяет нам держать нашу разработку отдельно от нашего производственного кода. -
Есть несколько ключевых функций, на которые стоит обратить внимание в IDE, прежде чем мы начнем работать. Это текстовый редактор, SQL и Python-исполнитель, а также CLI с управлением версиями Git, все в одном пакете! Это позволяет вам сосредоточиться на редактировании ваших SQL и Python файлов, предварительном просмотре результатов с помощью SQL-исполнителя (он даже выполняет Jinja!) и построении моделей в командной строке без необходимости переключаться между различными приложениями. Рабочий процесс Git в dbt Cloud позволяет как новичкам, так и экспертам Git легко управлять версиями всей своей работы с помощью нескольких кликов.
-
Давайте запустим наши первые модели dbt! В ваш проект dbt включены две примерные модели в папке
models/examples
, которые мы можем использовать для иллюстрации того, как запускать dbt в командной строке. Введитеdbt run
в командной строке и нажмите Enter на клавиатуре. Когда панель выполнения развернется, вы сможете увидеть результаты выполнения, где вы должны увидеть успешное завершение выполнения. -
Результаты выполнения позволяют вам увидеть код, который dbt компилирует и отправляет в Snowflake для выполнения. Чтобы просмотреть журналы этого выполнения, выберите одну из вкладок модели, используя значок >, а затем Details. Если вы немного прокрутите вниз, вы сможете увидеть скомпилированный код и то, как dbt взаимодействует с Snowflake. Поскольку это выполнение происходило в нашей среде разработки, модели были созданы в вашей схеме разработки.
-
Теперь давайте переключимся на Snowflake, чтобы подтвердить, что объекты действительно были созданы. Нажмите на три точки … над вашими объектами базы данных, а затем Refresh. Разверните базу данных PC_DBT_DB, и вы должны увидеть вашу схему разработки. Выберите схему, затем Tables и Views. Теперь вы должны увидеть
MY_FIRST_DBT_MODEL
как таблицу иMY_SECOND_DBT_MODEL
как представление.
Созд ание ветки и настройка конфигураций проекта
На этом этапе нам нужно создать ветку разработки и настроить конфигурации на уровне проекта.
-
Чтобы начать разработку нашего проекта, нам нужно создать новую ветку Git для нашей работы. Выберите create branch и назовите вашу ветку разработки. Мы назовем нашу ветку
snowpark_python_workshop
, затем нажмите Submit. -
Первым шагом в разработке проекта будет обновление файла
dbt_project.yml
. Каждый проект dbt требует наличия файлаdbt_project.yml
— это то, как dbt узнает, что каталог является проектом dbt. Файл dbt_project.yml также содержит важную информацию, которая сообщает dbt, как работать с вашим проектом. -
Выберите файл
dbt_project.yml
из дерева файлов, чтобы открыть его, и замените все существующее содержимое следующим кодом. Когда закончите, сохраните файл, нажав save. Вы также можете использовать сочетание клавиш Command-S или Control-S с этого момента.# Назовите ваш проект! Имена проектов должны содержать только строчные символы
# и подчеркивания. Хорошее имя пакета должно отражать название вашей организации
# или предполагаемое использование этих моделей
name: 'snowflake_dbt_python_formula1'
version: '1.3.0'
require-dbt-version: '>=1.3.0'
config-version: 2
# Эта настройка конфигурирует, какой "профиль" dbt использует для этого проекта.
profile: 'default'
# Эти конфигурации указывают, где dbt должен искать различные типы файлов.
# Конфигурация `model-paths`, например, указывает, что модели в этом проекте можно
# найти в каталоге "models/". Вероятно, вам не нужно будет их изменять!
model-paths: ["models"]
analysis-paths: ["analyses"]
test-paths: ["tests"]
seed-paths: ["seeds"]
macro-paths: ["macros"]
snapshot-paths: ["snapshots"]
target-path: "target" # каталог, который будет хранить скомпилированные SQL файлы
clean-targets: # каталоги, которые будут удалены командой `dbt clean`
- "target"
- "dbt_packages"
models:
snowflake_dbt_python_formula1:
staging:
+docs:
node_color: "CadetBlue"
marts:
+materialized: table
aggregates:
+docs:
node_color: "Maroon"
+tags: "bi"
core:
+docs:
node_color: "#800080"
intermediate:
+docs:
node_color: "MediumSlateBlue"
ml:
prep:
+docs:
node_color: "Indigo"
train_predict:
+docs:
node_color: "#36454f" -
Основные конфигурации, на которые стоит обратить внимание в файле в отношении работы, которую мы собираемся выполнить, находятся в разделе
models
.require-dbt-version
— Указывает dbt, какую версию dbt использовать для вашего проекта. Мы требуем 1.3.0 и любую более новую версию для запуска python моделей и цветов узлов.materialized
— Указывает dbt, как материализовать модели при компиляции кода перед его отправкой в Snowflake. Все модели в папкеmarts
будут построены как таблицы.tags
— Применяет теги на уровне каталога ко всем моделям. Все модели в папкеaggregates
будут помечены какbi
(сокращение от business intelligence).docs
— Указываетnode_color
либо по имени цвета, либо по значению hex.
-
Материализации — это стратегии для сохранения моделей dbt в хранилище, с
tables
иviews
как наиболее часто используемыми типами. По умолчанию все модели dbt материализуются как представления, и другие типы материализации могут быть настроены в файлеdbt_project.yml
или в самой модели. Очень важно отметить, что Python модели могут быть материализованы только как таблицы или инкрементальные модели. Поскольку все наши Python модели находятся вmarts
, следующая часть нашегоdbt_project.yml
гарантирует, что не возникнет ошибок при запуске наших Python моделей. Начиная с версии dbt 1.4, Python файлы автоматически материализуются как таблицы, даже если это не указано явно.marts:
+materialized: table
Создание папок и организация файлов
dbt Labs разработала руководство по структуре проекта, которое содержит ряд рекомендаций по построению структуры папок для вашего проекта. Обязательно ознакомьтесь с этим руководством, если хотите узнать больше. Сейчас мы создадим несколько папок для организации наших файлов:
- Источники — Это наш набор данных Формулы 1, и он будет определен в YAML файле источника.
- Модели подготовки — Эти модели имеют 1:1 с их исходн ой таблицей.
- Промежуточные — Здесь мы будем объединять некоторые модели подготовки Формулы.
- Модели Marts — Здесь мы выполняем наши основные преобразования. Он содержит следующие подпапки:
- aggregates
- core
- ml
-
В вашем дереве файлов используйте курсор и наведите на подкаталог
models
, нажмите на три точки …, которые появятся справа от имени папки, затем выберите Create Folder. Мы добавим две новые папки в путь к файлу,staging
иformula1
(в этом порядке), введяstaging/formula1
в путь к файлу.- Если вы откроете свой каталог
models
сейчас, вы должны увидеть новую папкуstaging
, вложенную вmodels
, и папкуformula1
, вложенную вstaging
.
- Если вы откроете свой каталог
-
Создайте две дополнительные папки так же, как и на предыдущем шаге. В подкаталоге
models
создайте новые каталогиmarts/core
. -
Нам нужно будет создать еще несколько папок и подпапок с помощью интерфейса. После того, как вы создадите все необходимые папки, ваше дерево папок должно выглядеть так, когда все будет готово:
Помните, что вы всегда можете обратиться к полному проекту на GitHub, чтобы просмотреть полную структуру папок и файлов.
Создание источников и моделей подготовки
В этом разделе мы создадим наши источники и модели подготовки.
Источники позволяют нам создать зависимость между нашим исходным объектом базы данных и нашими моделями подготовки, что поможет нам, когда мы будем смотреть на позже. Кроме того, если ваш источник изменяет базу данных или схему, вам нужно будет обновить его только в вашем файле f1_sources.yml
, а не обновлять все модели, в которых он может использоваться.
Модели подготовки являются основой нашего проекта, где мы собираем все отдельные компоненты, которые мы будем использовать для создания наших более сложных и полезных моделей в проект.
Поскольку мы хотим сосредоточиться на dbt и Python в этом воркшопе, ознакомьтесь с нашими источниками и документами по подготовке, если хотите узнать больше (или пройдите наш курс dbt Fundamentals, который охватывает все наши основные функции).
1. Создание источников
Мы будем использовать каждую из наших 8 таблиц Формулы 1 из нашей базы данных formula1
под схемой raw
для наших преобразований, и мы хотим создать эти таблицы как источники в нашем проекте.
- Создайте новый файл с именем
f1_sources.yml
с следующим путем к файлу:models/staging/formula1/f1_sources.yml
. - Затем вставьте следующий код в файл перед его сохранением:
version: 2
sources:
- name: formula1
description: формула 1 наборы данных с нормализованными таблицами
database: formula1
schema: raw
tables:
- name: circuits
description: Одна запись на трассу, которая является конкретной гоночной трассой.
columns:
- name: circuitid
tests:
- unique
- not_null
- name: constructors
description: Одна запись на конструктора. Конструкторы — это команды, которые строят свои автомобили Формулы 1.
columns:
- name: constructorid
tests:
- unique
- not_null
- name: drivers
description: Одна запись на водителя. Эта таблица содержит информацию о водителе.
columns:
- name: driverid
tests:
- unique
- not_null
- name: lap_times
description: Одна строка на круг в каждой гонке. Время круга начало записываться в этом наборе данных в 1984 году и соединяется через driver_id.
- name: pit_stops
description: Одна строка на пит-стоп. Пит-стопы не имеют собственного столбца id, комбинация race_id и driver_id идентифицирует пит-стоп.
columns:
- name: stop
tests:
- accepted_values:
values: [1,2,3,4,5,6,7,8]
quote: false
- name: races
description: Одна гонка на строку. Важно, что эта таблица содержит год гонки для понимания тенденций.
columns:
- name: raceid
tests:
- unique
- not_null
- name: results
columns:
- name: resultid
tests:
- unique
- not_null
description: Одна строка на результат. Основная таблица, которую мы соединяем для переменных сетки и позиции.
- name: status
description: Один статус на строку. Статус контекстуализирует, была ли гонка завершена или какие проблемы возникли, например, столкновения, двигатель и т.д.
columns:
- name: statusid
tests:
- unique
- not_null
2. Создание моделей подготовки
Следующим шагом будет настройка моделей подготовки для каждой из 8 исходных таблиц. Учитывая отношение один к одному между моделями подготовки и их соответствующими исходными таблицами, мы создадим здесь 8 моделей подготовки. Мы знаем, что это много, и в будущем мы постараемся обновить воркшоп, чтобы сделать этот шаг менее повторяющимся и более эффективным. Этот шаг также является хорошим представлением реального мира данных, где у вас есть несколько иерархических таблиц, которые вам нужно будет объединить!
-
Давайте пойдем в алфавитном порядке, чтобы легко отслеживать все наши модели подготовки! Создайте новый файл с именем
stg_f1_circuits.sql
с этим путем к файлуmodels/staging/formula1/stg_f1_circuits.sql
. Затем вставьте следующий код в файл перед его сохранением:with
source as (
select * from {{ source('formula1','circuits') }}
),
renamed as (
select
circuitid as circuit_id,
circuitref as circuit_ref,
name as circuit_name,
location,
country,
lat as latitude,
lng as longitude,
alt as altitude
-- omit the url
from source
)
select * from renamedВсе, что мы делаем здесь, это извлекаем исходные данные в модель, используя функцию
source
, переименовываем некоторые столбцы и пропускаем столбецurl
с комментарием, так как он нам не нужен для нашего анализа. -
Создайте
stg_f1_constructors.sql
с этим путем к файлуmodels/staging/formula1/stg_f1_constructors.sql
. Вставьте следующий код в него перед сохранением файла:with
source as (
select * from {{ source('formula1','constructors') }}
),
renamed as (
select
constructorid as constructor_id,
constructorref as constructor_ref,
name as constructor_name,
nationality as constructor_nationality
-- omit the url
from source
)
select * from renamedУ нас есть еще 6 моделей подготовки, которые нужно создать. Мы можем сделать это, создавая новые файлы, а затем копируя и вставляя код в нашу папку
staging
. -
Создайте
stg_f1_drivers.sql
с этим путем к файлуmodels/staging/formula1/stg_f1_drivers.sql
:with
source as (
select * from {{ source('formula1','drivers') }}
),
renamed as (
select
driverid as driver_id,
driverref as driver_ref,
number as driver_number,
code as driver_code,
forename,
surname,
dob as date_of_birth,
nationality as driver_nationality
-- omit the url
from source
)
select * from renamed -
Создайте
stg_f1_lap_times.sql
с этим путем к файлуmodels/staging/formula1/stg_f1_lap_times.sql
:with
source as (
select * from {{ source('formula1','lap_times') }}
),
renamed as (
select
raceid as race_id,
driverid as driver_id,
lap,
position,
time as lap_time_formatted,
milliseconds as lap_time_milliseconds
from source
)
select * from renamed -
Создайте
stg_f1_pit_stops.sql
с этим путем к файлуmodels/staging/formula1/stg_f1_pit_stops.sql
:with
source as (
select * from {{ source('formula1','pit_stops') }}
),
renamed as (
select
raceid as race_id,
driverid as driver_id,
stop as stop_number,
lap,
time as lap_time_formatted,
duration as pit_stop_duration_seconds,
milliseconds as pit_stop_milliseconds
from source
)
select * from renamed
order by pit_stop_duration_seconds desc -
Создайте
stg_f1_races.sql
с этим путем к файлуmodels/staging/formula1/stg_f1_races.sql
:with
source as (
select * from {{ source('formula1','races') }}
),
renamed as (
select
raceid as race_id,
year as race_year,
round as race_round,
circuitid as circuit_id,
name as circuit_name,
date as race_date,
to_time(time) as race_time,
-- omit the url
fp1_date as free_practice_1_date,
fp1_time as free_practice_1_time,
fp2_date as free_practice_2_date,
fp2_time as free_practice_2_time,
fp3_date as free_practice_3_date,
fp3_time as free_practice_3_time,
quali_date as qualifying_date,
quali_time as qualifying_time,
sprint_date,
sprint_time
from source
)
select * from renamed -
Создайте
stg_f1_results.sql
с этим путем к файлуmodels/staging/formula1/stg_f1_results.sql
:with
source as (
select * from {{ source('formula1','results') }}
),
renamed as (
select
resultid as result_id,
raceid as race_id,
driverid as driver_id,
constructorid as constructor_id,
number as driver_number,
grid,
position::int as position,
positiontext as position_text,
positionorder as position_order,
points,
laps,
time as results_time_formatted,
milliseconds as results_milliseconds,
fastestlap as fastest_lap,
rank as results_rank,
fastestlaptime as fastest_lap_time_formatted,
fastestlapspeed::decimal(6,3) as fastest_lap_speed,
statusid as status_id
from source
)
select * from renamed -
Последний! Создайте
stg_f1_status.sql
с этим путем к файлу:models/staging/formula1/stg_f1_status.sql
:with
source as (
select * from {{ source('formula1','status') }}
),
renamed as (
select
statusid as status_id,
status
from source
)
select * from renamedПосле завершения создания источника и всех моделей подготовки для каждой из 8 таблиц ваша папка подготовки должна выглядеть так:
-
Сейчас хорошее время, чтобы удалить нашу папку с примерами, так как эти две модели являются лишними для нашего конвейера formula1, и
my_first_model
не проходит тестnot_null
, который мы не будем исследовать. dbt Cloud предупредит нас, что эта папка будет удалена навсегда, и мы согласны с этим, поэтому выберите Delete. -
Теперь, когда модели подготовки созданы и сохранены, пришло время создать модели в нашей схеме разработки в Snowflake. Для этого мы введем в командной строке
dbt build
, чтобы запустить все модели в нашем проекте, включая 8 новых моделей подготовки и существующие модели примеров.Ваше выполнение должно завершиться успешно, и вы должны увидеть зеленые галочки рядом со всеми вашими моделями в результатах выполнения. Мы построили наши 8 моделей подготовки как представления и запустили 13 тестов источников, которые мы настроили в файле
f1_sources.yml
с не таким уж большим количеством кода, довольно круто!Давайте быстро взглянем на Snowflake, обновим объекты базы данных, откроем нашу схему разработки и подтвердим, что новые модели там. Если вы можете их увидеть, значит, все в порядке!
Прежде чем перейти к следующему разделу, обязательно зафиксируйте ваши новые модели в вашей ветке Git. Нажмите Commit and push и дайте вашему коммиту сообщение, например,
profile, sources, and staging setup
, прежде чем продолжить.
Преобразование SQL
Теперь, когда у нас есть все наши источники и модели подготовки, пришло время перейти к тому, где dbt сияет — преобразование!
Нам нужно:
- Создать некоторые промежуточные таблицы для объединения таблиц, которые не являются иерархическими
- Создать основные таблицы для загрузки в инструменты бизнес-аналитики (BI)
- Ответить на два вопроса о:
- самых быстрых пит-стопах
- тенденциях времени круга в данных Формулы 1, создавая агрегированные модели с использованием Python!
Промежуточные модели
Нам нужно объединить множество справочных таблиц с нашей таблицей результатов, чтобы создать читаемую человеком таблицу данных. Что это значит? Например, мы не хотим иметь только числовой status_id
в нашей таблице, мы хотим иметь возможность прочитать в строке данных, что водитель не смог завершить гонку из-за отказа двигателя (status_id=5
).
К настоящему моменту мы довольно хорошо умеем создавать новые файлы в правильных каталогах, поэтому не будем подробно останавливаться на этом. Все промежуточные модели должны быть созданы в пути models/intermediate
.
-
Создайте новый файл с именем
int_lap_times_years.sql
. В этой модели мы объединяем информацию о вр емени круга и гонках, чтобы мы могли смотреть на время круга за годы. В более ранние эпохи Формулы 1 время круга не записывалось (только окончательные результаты), поэтому мы отфильтровываем записи, где время круга равно null.with lap_times as (
select * from {{ ref('stg_f1_lap_times') }}
),
races as (
select * from {{ ref('stg_f1_races') }}
),
expanded_lap_times_by_year as (
select
lap_times.race_id,
driver_id,
race_year,
lap,
lap_time_milliseconds
from lap_times
left join races
on lap_times.race_id = races.race_id
where lap_time_milliseconds is not null
)
select * from expanded_lap_times_by_year -
Создайте файл с именем
in_pit_stops.sql
. Пит-стопы имеют отношение многие-к-одному (M:1) с нашими гонками. Мы создаем функциюtotal_pit_stops_per_race
, разделяя поrace_id
иdriver_id
, сохраняя при этом индивидуальные пит-стопы для скользящего среднего в нашем следующем разделе.with stg_f1__pit_stops as
(
select * from {{ ref('stg_f1_pit_stops') }}
),
pit_stops_per_race as (
select
race_id,
driver_id,
stop_number,
lap,
lap_time_formatted,
pit_stop_duration_seconds,
pit_stop_milliseconds,
max(stop_number) over (partition by race_id,driver_id) as total_pit_stops_per_race
from stg_f1__pit_stops
)
select * from pit_stops_per_race -
Создайте файл с именем
int_results.sql
. Здесь мы используем 4 наших таблицы —races
,drivers
,constructors
иstatus
— чтобы дать контекст нашей таблицеresults
. Теперь мы можем рассчитать новую функциюdrivers_age_years
, приведяdate_of_birth
иrace_year
в одну таблицу. Мы также создаем столбец, чтобы указать, не завершил ли водитель гонку, на основе того, была ли ихposition
равна null, называемогоdnf_flag
.with results as (
select * from {{ ref('stg_f1_results') }}
),
races as (
select * from {{ ref('stg_f1_races') }}
),
drivers as (
select * from {{ ref('stg_f1_drivers') }}
),
constructors as (
select * from {{ ref('stg_f1_constructors') }}
),
status as (
select * from {{ ref('stg_f1_status') }}
),
int_results as (
select
result_id,
results.race_id,
race_year,
race_round,
circuit_id,
circuit_name,
race_date,
race_time,
results.driver_id,
results.driver_number,
forename ||' '|| surname as driver,
cast(datediff('year', date_of_birth, race_date) as int) as drivers_age_years,
driver_nationality,
results.constructor_id,
constructor_name,
constructor_nationality,
grid,
position,
position_text,
position_order,
points,
laps,
results_time_formatted,
results_milliseconds,
fastest_lap,
results_rank,
fastest_lap_time_formatted,
fastest_lap_speed,
results.status_id,
status,
case when position is null then 1 else 0 end as dnf_flag
from results
left join races
on results.race_id=races.race_id
left join drivers
on results.driver_id = drivers.driver_id
left join constructors
on results.constructor_id = constructors.constructor_id
left join status
on results.status_id = status.status_id
)
select * from int_results -
Создайте Markdown файл
intermediate.md
, который мы подробно рассмотрим в разделах Тестирование и Документация руководства Использование dbt Cloud для создания аналитических и ML-готовых конвейеров с SQL и Python в Snowflake.# цель этого .md — позволить многострочные длинные объяснения для наших промежуточных преобразований
# ниже приведены описания
{% docs int_results %} В этом запросе мы хотим присоединить другую важную информацию о результатах гонок, чтобы иметь читаемую таблицу о результатах, гонках, водителях, конструкторах и статусе.
У нас будет 4 левых соединения с нашей таблицей результатов. {% enddocs %}
{% docs int_pit_stops %} В одной гонке много пит-стопов, то есть отношение M:1.
Мы хотим агрегировать это, чтобы мы могли правильно присоединить информацию о пит-стопах без создания фан-аута. {% enddocs %}
{% docs int_lap_times_years %} Время круга выполняется на круг. Нам нужно присоединить их к году гонки, чтобы понять тенденции времени круга за годы. {% enddocs %} -
Создайте YAML файл
intermediate.yml
, который мы подробно рассмотрим в разделах Тестирование и Документация руководства Использование dbt Cloud для создания аналитических и ML-готовых конвейеров с SQL и Python в Snowflake.version: 2
models:
- name: int_results
description: '{{ doc("int_results") }}'
- name: int_pit_stops
description: '{{ doc("int_pit_stops") }}'
- name: int_lap_times_years
description: '{{ doc("int_lap_times_years") }}'Это завершает промежуточные модели, которые нам нужно создать для наших основных моделей!
Основные модели
-
Создайте файл
fct_results.sql
. Это то, что я люблю называть "мега таблицей" — действительно большая денормализованная таблица со всем нашим контекстом, добавленным на уровне строк для читаемости человеком. Важно, что у нас есть таблицаcircuits
, которая связана через таблицуraces
. Когда мы присоединилиraces
кresults
вint_results.sql
, мы позволили нашим таблицам установить связь отcircuits
кresults
вfct_results.sql
. Мы берем информацию о пит-стопах только на уровне результатов, чтобы наше соединение не вызвало фан-аута.with int_results as (
select * from {{ ref('int_results') }}
),
int_pit_stops as (
select
race_id,
driver_id,
max(total_pit_stops_per_race) as total_pit_stops_per_race
from {{ ref('int_pit_stops') }}
group by 1,2
),
circuits as (
select * from {{ ref('stg_f1_circuits') }}
),
base_results as (
select
result_id,
int_results.race_id,
race_year,
race_round,
int_results.circuit_id,
int_results.circuit_name,
circuit_ref,
location,
country,
latitude,
longitude,
altitude,
total_pit_stops_per_race,
race_date,
race_time,
int_results.driver_id,
driver,
driver_number,
drivers_age_years,
driver_nationality,
constructor_id,
constructor_name,
constructor_nationality,
grid,
position,
position_text,
position_order,
points,
laps,
results_time_formatted,
results_milliseconds,
fastest_lap,
results_rank,
fastest_lap_time_formatted,
fastest_lap_speed,
status_id,
status,
dnf_flag
from int_results
left join circuits
on int_results.circuit_id=circuits.circuit_id
left join int_pit_stops
on int_results.driver_id=int_pit_stops.driver_id and int_results.race_id=int_pit_stops.race_id
)
select * from base_results -
Создайте файл
pit_stops_joined.sql
. Наши результаты и пит-стопы находятся на разных уровнях размерности (также называемых зернистостью). Проще говоря, у нас есть несколько пит-стопов на один результат. Поскольку мы заинтересованы в понимании информации на уровне пит-стопов с информацией о годе гонки и конструкторе, мы создадим новую таблицуpit_stops_joined.sql
, где каждая строка будет на пит-стоп. Наша новая таблица подготавливает нашу агрегацию в Python.with base_results as (
select * from {{ ref('fct_results') }}
),
pit_stops as (
select * from {{ ref('int_pit_stops') }}
),
pit_stops_joined as (
select
base_results.race_id,
race_year,
base_results.driver_id,
constructor_id,
constructor_name,
stop_number,
lap,
lap_time_formatted,
pit_stop_duration_seconds,
pit_stop_milliseconds
from base_results
left join pit_stops
on base_results.race_id=pit_stops.race_id and base_results.driver_id=pit_stops.driver_id
)
select * from pit_stops_joined -
Введите в командной строке и выполните
dbt build
, чтобы построить весь наш конвейер до этого момента. Не беспокойтесь о "перезаписи" ваших предыдущих моделей – рабочие процессы dbt разработаны так, чтобы быть идемпотентными, поэтому мы можем запускать их снова и ожидать тех же результатов. -
Давайте поговорим о нашей родословной до сих пор. Она выглядит хорошо 😎. Мы показали, как SQL можно использовать для изменения типа данных, имен столбцов и обработки иерархических соединений очень хорошо; все это время строя нашу автоматизированную родословную!
-
Время Commit and push наших изменений и дайте вашему коммиту сообщение, например,
intermediate and fact models
, прежде чем продолжить.
Запуск моделей dbt Python
До сих пор SQL управлял проектом (автомобильная игра слов намерена) для очистки данных и иерархических соединений. Теперь пришло время Python взять на себя управление (автомобильная игра слов все еще намерена) на оставшуюся часть нашей лаборатории! Для получения дополнительной информации о запуске Python моделей на dbt ознакомьтесь с нашими документами. Чтобы узнать больше о том, как работает dbt python под капотом, ознакомьтесь с Snowpark for Python, который делает возм ожным запуск dbt Python моделей.
Существует довольно много различий между SQL и Python с точки зрения синтаксиса dbt и DDL, поэтому мы будем разбивать наш код и выполнение моделей дальше для наших python моделей.
Анализ пит-стопов
Сначала мы хотим узнать: какой конструктор имел самые быстрые пит-стопы в 2021 году? (конструктор — это команда Формулы 1, которая строит или "конструирует" автомобиль).
-
Создайте новый файл с именем
fastest_pit_stops_by_constructor.py
в нашей папкеaggregates
(это первый раз, когда мы используем расширение.py
). -
Скопируйте следующий код в файл:
import numpy as np
import pandas as pd
def model(dbt, session):
# dbt configuration
dbt.config(packages=["pandas","numpy"])
# get upstream data
pit_stops_joined = dbt.ref("pit_stops_joined").to_pandas()
# provide year so we do not hardcode dates
year=2021
# describe the data
pit_stops_joined["PIT_STOP_SECONDS"] = pit_stops_joined["PIT_STOP_MILLISECONDS"]/1000
fastest_pit_stops = pit_stops_joined[(pit_stops_joined["RACE_YEAR"]==year)].groupby(by="CONSTRUCTOR_NAME")["PIT_STOP_SECONDS"].describe().sort_values(by='mean')
fastest_pit_stops.reset_index(inplace=True)
fastest_pit_stops.columns = fastest_pit_stops.columns.str.upper()
return fastest_pit_stops.round(2) -
Давайте разберем, что делает этот код шаг за шагом:
- Сначала мы импортируем библиотеки Python, которые мы используем. Библиотека — это повторно используемый фрагмент кода, написанный кем-то другим, который вы можете захотеть включить в свои программы/проекты. Мы используем
numpy
иpandas
в этой Python модели. Это похоже на пакет dbt, но наши библиотеки Python не сохраняются по всему проекту. - Определяем функцию с именем
model
с параметрамиdbt
иsession
. Параметрdbt
— это класс, скомпилированный dbt, который позволяет вам запускать ваш Python код в контексте вашего проекта dbt и DAG. Параметрsession
— это класс, представляющий соединение вашего Snowflake с бэкэндом Python. Функцияmodel
должна возвращать один DataFrame. Вы можете видеть, что все преобразования данных происходят в теле функцииmodel
, к которой привязано выражениеreturn
. - Затем, в контексте нашей библиотеки моделей dbt, мы передаем конфигурацию, какие пакеты нам нужны, используя
dbt.config(packages=["pandas","numpy"])
. - Используйте функцию
.ref()
, чтобы получить фрейм данныхpit_stops_joined
, который мы создали на предыдущем шаге, используя SQL. Мы приводим его к pandas dataframe (по умолчанию это Snowpark Dataframe). - Создайте переменную с именем
year
, чтобы мы не передавали жестко закодированное значение. - Создайте новый столбец с именем
PIT_STOP_SECONDS
, разделив значениеPIT_STOP_MILLISECONDS
на 1000. - Создайте наш окончательный фрейм данных
fastest_pit_stops
, который содержит записи, где год равен нашей переменной года (в данном случае 2021), затем сгруппируйте фрейм данных поCONSTRUCTOR_NAME
и используйте методыdescribe()
иsort_values()
в порядке убывания. Это сделает нашу первую строку в новом агрегированном фрейме данных командой с самыми быстрыми пит-стопами за весь год соревнований. - Наконец, он сбрасывает индекс фрейма данных
fastest_pit_stops
. Методreset_index()
позволяет сбросить индекс обратно к значениям по умолчанию 0, 1, 2 и т. д.; чтобы избежать этого, используйте параметр drop. Подумайте об этом как о сохранении ва ших данных "плоскими и квадратными", а не "многоуровневыми". Если вы новичок в Python, сейчас может быть хорошее время узнать об индексах за 5 минут, так как это основа того, как Python извлекает, нарезает и обрабатывает данные. Аргументinplace
означает, что мы перезаписываем существующий фрейм данных навсегда. Не бойтесь! Это то, что мы хотим сделать, чтобы избежать работы с многоиндексными фреймами данных! - Преобразуйте наши имена столбцов Python в верхний регистр, используя
.upper()
, чтобы Snowflake их распознал. - Наконец, мы возвращаем наш фрейм данных с двумя десятичными знаками для всех столбцов, используя метод
round()
.
- Сначала мы импортируем библиотеки Python, которые мы используем. Библиотека — это повторно используемый фрагмент кода, написанный кем-то другим, который вы можете захотеть включить в свои программы/проекты. Мы используем
-
Если взглянуть на это немного шире, что мы делаем по-другому здесь в Python по сравнению с нашим типичным SQL кодом:
- Цепочка методов — это техника, при которой несколько методов вызываются на объекте в одном выражении, при этом каждый вызов метода изменяет результат предыдущего. Методы вызываются в цепочке, при этом вывод одного метода используется в качестве ввода для след ующего. Эта техника используется для упрощения кода и повышения его читаемости за счет устранения необходимости в промежуточных переменных для хранения промежуточных результатов.
- Способ, которым вы видите цепочку методов в Python, — это синтаксис
.().()
. Например,.describe().sort_values(by='mean')
, где метод.describe()
связан с.sort_values()
.
- Способ, которым вы видите цепочку методов в Python, — это синтаксис
- Метод
.describe()
используется для генерации различных статистических данных о наборе данных. Он используется на pandas dataframe. Он дает быстрый и простой способ получить статистику вашего набора данных без написания нескольких строк кода. - Метод
.sort_values()
используется для сортировки pandas dataframe или серии по одному или нескольким столбцам. Метод сортирует данные по указанным столбцам в порядке возрастания или убывания. Это эквивалентorder by
в SQL.
Мы не будем так подробно разбирать наши последующие скрипты, но продолжим объяснять на высоком уровне, что делают новые библиотеки, функции и методы.
- Цепочка методов — это техника, при которой несколько методов вызываются на объекте в одном выражении, при этом каждый вызов метода изменяет результат предыдущего. Методы вызываются в цепочке, при этом вывод одного метода используется в качестве ввода для след ующего. Эта техника используется для упрощения кода и повышения его читаемости за счет устранения необходимости в промежуточных переменных для хранения промежуточных результатов.
-
Постройте модель, используя интерфейс, который выполнит:
dbt run --select fastest_pit_stops_by_constructor
в командной строке.
Давайте посмотрим на некоторые детали нашей первой Python модели, чтобы увидеть, что наша модель выполнила. Существует два основных различия, которые мы можем увидеть при запуске Python модели по сравнению с SQL моделью:
- Наша Python модель была выполнена как хранимая процедура. Snowflake нужно знать, что этот код предназначен для выполнения в среде выполнения Python, а не для интерпретации в среде выполнения SQL. Мы делаем это, создавая хранимую процедуру Python, вызываемую SQL командой.
- Библиотека
snowflake-snowpark-python
была выбрана для выполнения нашего Python кода. Хотя это не было явно указано, это выбирается объектом класса dbt, потому что нам нужен наш пакет Snowpark для выполнения Python!
Python модели выполняются немного дольше, чем SQL модели, однако мы всегда можем ускорить это, используя Snowpark-оптимизированные склады, если захотим. Наши данные достаточно малы, поэтому мы не будем беспокоиться о создании отдельного склада для Python по сравнению с SQL файлами сегодня.
Мы можем видеть, что наша python модель выполняется как хранимая процедура в нашей личной схеме разработкиОстальная часть нашего Details вывода дает нам информацию о том, как dbt и Snowpark для Python работают вместе, чтобы определить объекты класса и применить определенный набор методов для выполнения наших моделей.
Итак, какой конструктор имел самые быстрые пит-стопы в 2021 году? Давайте посмотрим на наши данные, чтобы узнать!
-
Мы не можем предварительно просмотреть Python модели напрямую, поэтому давайте создадим новый файл, используя кнопку + или сочетание клавиш Control-n, чтобы создать новый черновик.
-
Сошлитесь на нашу Python модель:
select * from {{ ref('fastest_pit_stops_by_constructor') }}
и предварительно просмотрите вывод:
Red Bull не только имел самые быстрые средние пит-стопы почти на 40 секунд, но и имел наименьшее стандартное отклонение, что означает, что они являются как самыми быстрыми, так и самыми последовательными командами в пит-стопах. Используя метод
.describe()
, мы смогли избежать многословного SQL, требующего создания строки кода на столбец и повторного использования функцииPERCENTILE_COUNT()
.Теперь мы хотим найти среднее время круга и скользящее среднее за годы (в целом оно увеличивается или уменьшается)?
-
Создайте новый файл с именем
lap_times_moving_avg.py
в нашей папкеaggregates
. -
Скопируйте следующий код в файл:
import pandas as pd
def model(dbt, session):
# dbt configuration
dbt.config(packages=["pandas"])
# get upstream data
lap_times = dbt.ref("int_lap_times_years").to_pandas()
# describe the data
lap_times["LAP_TIME_SECONDS"] = lap_times["LAP_TIME_MILLISECONDS"]/1000
lap_time_trends = lap_times.groupby(by="RACE_YEAR")["LAP_TIME_SECONDS"].mean().to_frame()
lap_time_trends.reset_index(inplace=True)
lap_time_trends["LAP_MOVING_AVG_5_YEARS"] = lap_time_trends["LAP_TIME_SECONDS"].rolling(5).mean()
lap_time_trends.columns = lap_time_trends.columns.str.upper()
return lap_time_trends.round(1) -
Разбирая наш код немного:
- Мы используем только библиотеку
pandas
для этой модели и приводим ее к pandas dataframe.to_pandas()
. - Создайте новый столбец с именем
LAP_TIMES_SECONDS
, разделив значениеLAP_TIME_MILLISECONDS
на 1000. - Создайте окончательный фрейм данных. Получите время круга за год. Рассчитайте среднюю серию и преобразуйте в фрейм данных.
- Сбросьте индекс.
- Рассчитайте скользящее среднее за 5 лет.
- Округлите наши числовые столбцы до одного десятичного знака.
- Мы используем только библиотеку
-
Теперь запустите эту модель, используя интерфейс Run model или
dbt run --select lap_times_moving_avg
в командной строке.
-
Еще раз предварительно просматривая вывод наших данных, используя те же шаги для нашей модели
fastest_pit_stops_by_constructor
.