#видео #моксобес
Подвёз контент под вечер. Пятый выпуск серии мок-собесов на youtube
-> Ссылка на видео (youtube)
-> Ссылка на видео (vk video)
Подвёз контент под вечер. Пятый выпуск серии мок-собесов на youtube
-> Ссылка на видео (youtube)
-> Ссылка на видео (vk video)
YouTube
Мок-собеседование на junior+ Data Engineer S1E5 | rzv_de | Aug 2024
Погружаемся в роли интервьюера и кандидата на час, плотная получасовая обратная связь уже выложена на бусти.
https://boosty.to/rzv_de
Я не представляю компанию из интервью, вакансия выбрана кандидатом для тренировки.
Послушал про опыт кандидата, копнули…
https://boosty.to/rzv_de
Я не представляю компанию из интервью, вакансия выбрана кандидатом для тренировки.
Послушал про опыт кандидата, копнули…
Завтра, в субботу 7 сентября, в 12:00 мск будет стрим-интервью с @digitalberd
Расскажу о своём пути, почему и как пришёл в менторство и в инженерию данных, затронем ещё пару тем.
https://www.youtube.com/live/Zh5WGo18-L8?si=OicFyIX2nr6VFHmE
Стрим начинается!
Расскажу о своём пути, почему и как пришёл в менторство и в инженерию данных, затронем ещё пару тем.
https://www.youtube.com/live/Zh5WGo18-L8?si=OicFyIX2nr6VFHmE
Стрим начинается!
Александр вёл нешуточную борьбу с техническими неполадками.
Часть стрима провели в онлайне, но потом он всё же упал. Ссылка на то, что удалось спасти, в комментах.
Разошлись немного ожидания с Александром по формату, оказалось что это не совсем интервью.
Возможно проведу часть два так, как я сам это вижу. Stay tuned
Часть стрима провели в онлайне, но потом он всё же упал. Ссылка на то, что удалось спасти, в комментах.
Разошлись немного ожидания с Александром по формату, оказалось что это не совсем интервью.
Возможно проведу часть два так, как я сам это вижу. Stay tuned
Youtube
- YouTube
Enjoy the videos and music you love, upload original content, and share it all with friends, family, and the world on YouTube.
#видео #моксобес
Шестой выпуск серии мок-собесов на youtube
-> Ссылка на видео (youtube)
-> Ссылка на видео (vk video)
Шестой выпуск серии мок-собесов на youtube
-> Ссылка на видео (youtube)
-> Ссылка на видео (vk video)
YouTube
Мок-собеседование на middle Data Engineer S1E6 | rzv_de | Sep 2024
Погружаемся в роли интервьюера и кандидата на час, плотная получасовая обратная связь уже выложена на бусти. Там же ищи код задач.
https://boosty.to/rzv_de
Я не представляю компанию из интервью, вакансия выбрана кандидатом для тренировки.
Послушал про…
https://boosty.to/rzv_de
Я не представляю компанию из интервью, вакансия выбрана кандидатом для тренировки.
Послушал про…
#зачем_нужно
Кастомные материализации в dbt: мощный инструмент или поворот не туда? 1/2
🔸 dbt предоставляет стандартные материализации (table, view, incremental, ephemeral), которые покрывают большинство сценариев. Но иногда возникает потребность в чем-то особенном. Как и в airflow, в dbt можно переопределить всё что угодно и написать свою имплементацию Х, подложив код в папку с проектом.
🔸 Когда стоит задуматься о кастомных материализациях?
* Специфические требования к производительности
* Уникальные особенности вашего DWH
* Сложная бизнес-логика, выходящая за рамки стандартных подходов
* Необходимость в повторяющихся паттернах, которые не покрываются существующими материализациями. Например, когда при
🔸 Важно помнить: кастомные материализации гарантированно усложнят проект, а полезными не факт, что будут. Перед их внедрением задай себе несколько вопросов:
* Действительно ли стандартные материализации не справляются с задачей? Может, я "не умею их готовить"?
* Можно ли решить проблему с помощью post-hooks или pre-hooks?
* Готова ли команда поддерживать кастомный код в долгосрочной перспективе?
🔸 Когда лучше воздержаться от кастомных материализаций:
* Команда не имеет глубокого понимания dbt и SQL или её воротит от одной мысли поддержки pascal-like скриптов
* Проект часто мигрирует между разными типами баз данных
* Нет четкого плана по поддержке и обновлению кастомного кода
* Кастомизация требуется только для одной или двух моделей
Кастомные материализации в dbt: мощный инструмент или поворот не туда? 1/2
🔸 dbt предоставляет стандартные материализации (table, view, incremental, ephemeral), которые покрывают большинство сценариев. Но иногда возникает потребность в чем-то особенном. Как и в airflow, в dbt можно переопределить всё что угодно и написать свою имплементацию Х, подложив код в папку с проектом.
🔸 Когда стоит задуматься о кастомных материализациях?
* Специфические требования к производительности
* Уникальные особенности вашего DWH
* Сложная бизнес-логика, выходящая за рамки стандартных подходов
* Необходимость в повторяющихся паттернах, которые не покрываются существующими материализациями. Например, когда при
full-refresh
нужно добавить промежуточные шаги для backfill'a или хочется добавить возможность скастить поле в table
без пересчёта.🔸 Важно помнить: кастомные материализации гарантированно усложнят проект, а полезными не факт, что будут. Перед их внедрением задай себе несколько вопросов:
* Действительно ли стандартные материализации не справляются с задачей? Может, я "не умею их готовить"?
* Можно ли решить проблему с помощью post-hooks или pre-hooks?
* Готова ли команда поддерживать кастомный код в долгосрочной перспективе?
🔸 Когда лучше воздержаться от кастомных материализаций:
* Команда не имеет глубокого понимания dbt и SQL или её воротит от одной мысли поддержки pascal-like скриптов
* Проект часто мигрирует между разными типами баз данных
* Нет четкого плана по поддержке и обновлению кастомного кода
* Кастомизация требуется только для одной или двух моделей
Кастомные материализации в dbt: мощный инструмент или поворот не туда? 2/2
Пример базовой кастомной материализации
Тогда модель
В реальных сценариях нужно добавить специфичную для адаптера логику (например, через макросы и adapter-dispatch) или дополнительные шаги обработки. Изучи реализации, поставленные "из коробки", прежде чем писать своё :)
❔А тебе приходилось сталкиваться с ситуациями, когда кастомные материализации реально спасли проект? Или, может быть, наоборот, усложнили его до невозможности? Поделись опытом в комментариях!
Пример базовой кастомной материализации
my_project/macros/my_materialization.sql
:{% materialization custom_table, default %}
{%- set target_relation = this.incorporate(type='table') %}
{{ run_hooks(pre_hooks) }}
-- в main нужно обязательно сформировать код, который отправится в `target/compile` и `target/run` директории для этой модельки
{% call statement('main') -%}
{{ create_table_as(target_relation, sql) }}
{%- endcall %}
{{ run_hooks(post_hooks) }}
{{ return({'relations': [target_relation]}) }}
{% endmaterialization %}
Тогда модель
my_project/models/my_model.sql
будет выглядеть так:{{ config(materialized='custom_table') }}
select *
from {{ source("default", "my_raw_model") }}
В реальных сценариях нужно добавить специфичную для адаптера логику (например, через макросы и adapter-dispatch) или дополнительные шаги обработки. Изучи реализации, поставленные "из коробки", прежде чем писать своё :)
❔А тебе приходилось сталкиваться с ситуациями, когда кастомные материализации реально спасли проект? Или, может быть, наоборот, усложнили его до невозможности? Поделись опытом в комментариях!
Getdbt
About dispatch config | dbt Developer Hub
dbt extends functionality across data platforms using multiple dispatch.
#видео #моксобес
Ты знаешь, что с этим делать
-> Ссылка на видео (youtube)
-> Ссылка на видео (vk video)
Ты знаешь, что с этим делать
-> Ссылка на видео (youtube)
-> Ссылка на видео (vk video)
YouTube
Мок-собеседование на senior? Data Engineer S1E7 | rzv_de | Oct 2024
Погружаемся в роли интервьюера и кандидата на час, плотная 45-минутная обратная связь уже выложена на бусти.
https://boosty.to/rzv_de
Послушал про опыт кандидата, в этот раз 100% теории, без задач.
Делись с заинтересованными, если понравилось и хочешь…
https://boosty.to/rzv_de
Послушал про опыт кандидата, в этот раз 100% теории, без задач.
Делись с заинтересованными, если понравилось и хочешь…
Пока не вернул настрой на регулярные посты, мидлам и сеньорам рекомендую канал Василия Трещева по техническим нюансам работы greenplum.
Он крутой инженер "старой закалки", который в любой непонятной ситуации читает исходный код.
https://www.tgoop.com/GreenplumSQLClub
Он крутой инженер "старой закалки", который в любой непонятной ситуации читает исходный код.
https://www.tgoop.com/GreenplumSQLClub
Telegram
GreenplumSQLClub
Канал посвящен рецептам и практикам по работе с Greenplum / Arenadata DB
Наш основной канал https://www.tgoop.com/sqlclub_ru
Если будут рецепты для истории можно написать в личку @SQL4Life
Наш основной канал https://www.tgoop.com/sqlclub_ru
Если будут рецепты для истории можно написать в личку @SQL4Life
#термин_дня
Кратко о видах Executor в Airflow
Экзекьютор это компонент Airflow, который определяет, где и как будет запущен таск дага.
На момент написания поста (airflow 2.10) есть 4 основных варианта:
🔸 SequentialExecutor — включён по умолчанию, очень медленный, простой как палка. Плох даже для локальных дев-стендов и пет-проектов.
🔸 LocalExecutor — работает как часть Scheduler'a и не требует отдельных сервисов-воркеров. Поддерживает параллельный запуск, отлично подходит для локальной отладки и небольших дев-стендов.
🔸 CeleryExecutor использует Redis или RabbitMQ в качестве бэкенда для координации тасков между пред-настроенными воркерами. Отлично подходит для большого объёма коротких тасок. Также есть полезный UI flower для мониторинг, который можно запустить отдельным процессом. По моему опыту, Celery воркеры обычно запускаются на виртуальных машинах.
Ограничения: все воркеры должны быть строго одинаково настроены, включая набор и версии python пакетов и всяких CLI, синхронизацию DAGS_FOLDER (обычно через гит). Есть возможность обойти, но это сильно усложнит поддержку.
🔸 KubernetesExecutor — запускает отдельный под в K8s для каждой таски, можно выделить больше ресурсов для тяжёлых задач. Под уничтожается после окончания работы таски.
Этот режим добавляет накладные расходы (десятки секунд) на запуск и остановку подов, что лучше подходит для длинных и редко запускаемых задач. Серия мелких тасок будет тормозить. Зато можно высвобождать ресурсы и не платить 24/7 за простой воркеров.
🔸 И, как со всем в Airflow, можно написать свой Executor. Но должна быть уверенность, что задачу не получится решить через стандартные.
Для дочитавших бонус: с v2.10 можно сконфигурировать несколько экзекьюторов параллельно и назначать для каждой таски свой тип — или Celery, или K8s. Есть даже гибриды вида CeleryKubernetesExecutor, но они не рекомендуются командой Airflow.
❕Напиши в комментах, какие у тебя весёлые истории встречались с K8s экзекьютором, если используешь на проде :)
Кратко о видах Executor в Airflow
Экзекьютор это компонент Airflow, который определяет, где и как будет запущен таск дага.
На момент написания поста (airflow 2.10) есть 4 основных варианта:
🔸 SequentialExecutor — включён по умолчанию, очень медленный, простой как палка. Плох даже для локальных дев-стендов и пет-проектов.
🔸 LocalExecutor — работает как часть Scheduler'a и не требует отдельных сервисов-воркеров. Поддерживает параллельный запуск, отлично подходит для локальной отладки и небольших дев-стендов.
🔸 CeleryExecutor использует Redis или RabbitMQ в качестве бэкенда для координации тасков между пред-настроенными воркерами. Отлично подходит для большого объёма коротких тасок. Также есть полезный UI flower для мониторинг, который можно запустить отдельным процессом. По моему опыту, Celery воркеры обычно запускаются на виртуальных машинах.
Ограничения: все воркеры должны быть строго одинаково настроены, включая набор и версии python пакетов и всяких CLI, синхронизацию DAGS_FOLDER (обычно через гит). Есть возможность обойти, но это сильно усложнит поддержку.
🔸 KubernetesExecutor — запускает отдельный под в K8s для каждой таски, можно выделить больше ресурсов для тяжёлых задач. Под уничтожается после окончания работы таски.
Этот режим добавляет накладные расходы (десятки секунд) на запуск и остановку подов, что лучше подходит для длинных и редко запускаемых задач. Серия мелких тасок будет тормозить. Зато можно высвобождать ресурсы и не платить 24/7 за простой воркеров.
🔸 И, как со всем в Airflow, можно написать свой Executor. Но должна быть уверенность, что задачу не получится решить через стандартные.
Для дочитавших бонус: с v2.10 можно сконфигурировать несколько экзекьюторов параллельно и назначать для каждой таски свой тип — или Celery, или K8s. Есть даже гибриды вида CeleryKubernetesExecutor, но они не рекомендуются командой Airflow.
❕Напиши в комментах, какие у тебя весёлые истории встречались с K8s экзекьютором, если используешь на проде :)
Эксперимент — серия постов будет выходить средними кусочками несколько дней подряд
#зачем_нужно
Проблемы и решения в очистке данных 1/?
При загрузке данных из исходных систем мы почти всегда сталкиваемся с "грязными" данными - опечатки, разные форматы, технические ошибки. Если не обработать такие случаи, таблицы перестанут джойниться или будут выдавать мусор на выходе (в BI, отчётах и пр.).
Изучение и очистка данных на первом этапе помогает избежать неприятных сюрпризов в будущем и сэкономить время на исправлении ошибок. Вот основные трансформации, с которыми ты можешь столкнуться. Синтаксис стараюсь брать из ANSI или распространённых надстроек:
🔶 Название поля не соответствует naming convention в DWH
Лучше хотя бы на raw слое оставить исходные названия колонок для lineage и traceability. И старайся не множить сущности, где возможно, приводи к единому стилю (naming convention) и называй одинаковые параметры одинаково, а разные — по-разному.
🔶 Формат даты
🔶 JSON, который нужно распарсить и разложить по колонкам
Не забывай обрабатывать случаи с пустыми JSON'ами и массивами.
🔶 Вручную заполняемые поля "перечисляемого типа", которые нужно привести к одному виду
Использовать нечёткое сопоставление, например splink на python, или вручную заполненный маппинг значений, предварительно приведённых к
Написание запросов а-ля
#зачем_нужно
Проблемы и решения в очистке данных 1/?
При загрузке данных из исходных систем мы почти всегда сталкиваемся с "грязными" данными - опечатки, разные форматы, технические ошибки. Если не обработать такие случаи, таблицы перестанут джойниться или будут выдавать мусор на выходе (в BI, отчётах и пр.).
Изучение и очистка данных на первом этапе помогает избежать неприятных сюрпризов в будущем и сэкономить время на исправлении ошибок. Вот основные трансформации, с которыми ты можешь столкнуться. Синтаксис стараюсь брать из ANSI или распространённых надстроек:
🔶 Название поля не соответствует naming convention в DWH
column as new_column
Лучше хотя бы на raw слое оставить исходные названия колонок для lineage и traceability. И старайся не множить сущности, где возможно, приводи к единому стилю (naming convention) и называй одинаковые параметры одинаково, а разные — по-разному.
🔶 Формат даты
try_cast(date_column as date) /* для безопасного приведения */
to_date(date_string, 'YYYY-MM-DD') /* если известен формат */
case when date_column ~ '^\d{4}-\d{2}-\d{2}$' then cast(date_column as date) end /* с валидацией */
🔶 JSON, который нужно распарсить и разложить по колонкам
case when is_valid_json(json_column) then /* проверка валидности */
json_value(json_column, '$.field_name'),
json_query(json_column, '$.contacts[*].phone'), /* массив */
json_value(json_column, '$.address.city'), /* вложенный объект */
(select string_agg(value, ',')
from json_table(json_column, '$.tags[*]' columns (value varchar path '$'))
) as tags /* массив в строку */
end
Не забывай обрабатывать случаи с пустыми JSON'ами и массивами.
🔶 Вручную заполняемые поля "перечисляемого типа", которые нужно привести к одному виду
Использовать нечёткое сопоставление, например splink на python, или вручную заполненный маппинг значений, предварительно приведённых к
trim(upper(replace(column, ' ', '')))
или другому подобному формату. Написание запросов а-ля
lower(col) like '%sub%string%'
плохо масштабируется и зачастую приводит к неожиданным результатам (когда под шаблон начинают попадать "не те" категории).#зачем_нужно
Проблемы и решения в очистке данных 2/?
🔶 Значение "по умолчанию" для отсутствия данных в виде пустой строки или "Nan", когда для обработки нужен NULL
🔶 Разный тип данных при union/union all или колонок из условия on в join
🔶 Вставка в таргет-таблицу NOT NULL поля из источника, где значение может отсутствовать
🔶 У одного из объектов, объединяемых через union/union all, не достаёт колонки
🔶 Разъединить одну колонку на несколько
🔶 Объединить несколько колонок в одну
❔А в этом посте уже было что-то новое? Делись в комментах
Проблемы и решения в очистке данных 2/?
🔶 Значение "по умолчанию" для отсутствия данных в виде пустой строки или "Nan", когда для обработки нужен NULL
case when trim(lower(column)) in (
'', 'null', 'none', 'n/a', 'na', '-',
'#n/a', '#н/д', '(empty)', 'undefined'
) or column ~ '^\s*$' /* только пробелы */
then null
else column
end as clean_column
🔶 Разный тип данных при union/union all или колонок из условия on в join
case when numeric_col ~ '^\d+(\.\d+)?$'
then cast(numeric_col as decimal(18,2))
else null
end /* для последующих join по числовым полям */
cast(num_id as varchar(20)) as num_id /* для join,
где с одной стороны поле varchar(20), а в другой -- числа */
union example:
select cast(id as varchar) as id, name from table1
union all
select id, name from table2 /* приводим к более широкому типу */
case when try_cast(date_field as date) is not null
then try_cast(date_field as date)
else try_cast(date_field as timestamp)::date
end /* для разных форматов дат */
🔶 Вставка в таргет-таблицу NOT NULL поля из источника, где значение может отсутствовать
coalesce(column, 'default') as column
🔶 У одного из объектов, объединяемых через union/union all, не достаёт колонки
cast(null as [data_type]) as column /* null может быть разных типов */
🔶 Разъединить одну колонку на несколько
split_part(full_name, ' ', 1) as surname,
split_part(full_name, ' ', 2) as name /* наивный подход,
для каждого отдельного случая может быть сильно сложнее, вплоть до регулярок */
🔶 Объединить несколько колонок в одну
concat_ws(' ', nullif(address_line_1, ''), nullif(address_line_2, '')) as address
❔А в этом посте уже было что-то новое? Делись в комментах
#зачем_нужно
Проблемы и решения в очистке данных 3/?
🔶 Даты из далёкого будущего или прошлого
🔶 Объединить значения из нескольких строк в один массив
🔶 Полные дубли (совпадают все поля)
❔ Вопрос со звёздочкой*: какая разница между distinct и group by в этом примере?
🔶 Неполные дубли (различаются технические поля)
❕ А здесь было что-то, что пригодится уже завтра на работе?
Проблемы и решения в очистке данных 3/?
🔶 Даты из далёкого будущего или прошлого
case
when date_column between '1900-01-01' and '2100-12-31'
then date_column
else cast(null as date)
end as valid_date /* уточняй, как должно быть
по бизнес-требованиям. иногда даты из средне-далёкого
будущего это ок, например "плановая дата закрытия ипотеки" */
🔶 Объединить значения из нескольких строк в один массив
select key,
string_agg(values, ',')
from ...
group by key
🔶 Полные дубли (совпадают все поля)
select distinct col1, col2, col3
from table
/* или */
select col1, col2, col3
from table
group by col1, col2, col3
❔ Вопрос со звёздочкой*: какая разница между distinct и group by в этом примере?
🔶 Неполные дубли (различаются технические поля)
with prep_cte as (
select col1, col2, business_key, updated_at,
row_number() over (
partition by business_key
order by coalesce(updated_at, '1900-01-01') desc
) as rn
from table
)
select * from prep_cte
where rn = 1
/* оставляем последнюю версию строки по каждому бизнес-ключу */
❕ А здесь было что-то, что пригодится уже завтра на работе?
#зачем_нужно
Проблемы и решения в очистке данных 4/4
🔶 Нормализация unicode символов
❔ Рассказать в следующем посте про colation настройки БД (или почему иногда сортировка одних и тех же данных может выдавать разный результат) ? :)
🔶 Конвертация часовых поясов
🔶 Обработка спецсимволов в текстовых полях
🔶 Приведение булевых значений к стандартному виду
❕Ну что, как тебе формат? Голосуй реактами и комментами, если хочешь больше такого
Проблемы и решения в очистке данных 4/4
🔶 Нормализация unicode символов
translate(column, 'áéíóúàèìòùãẽĩõũâêîôûäëïöüçñ', 'aeiouaeiouaeiouaeiouaeioucn')
regexp_replace(column, '[^\x00-\x7F]+', '') /* удаление не ASCII символов */
❔ Рассказать в следующем посте про colation настройки БД (или почему иногда сортировка одних и тех же данных может выдавать разный результат) ? :)
🔶 Конвертация часовых поясов
select timestampz_column at time zone 'Europe/Moscow'
coalesce(
try_cast(timestamp_column as timestamp with time zone),
timestamp_column::timestamp at time zone 'UTC'
) /* если не всегда указана временная зона */
🔶 Обработка спецсимволов в текстовых полях
regexp_replace(column, '[^a-zA-Z0-9\s]', '') /* только буквы, цифры и пробелы */
translate(column, '[]{}()*#$%@!?+=/\|', '') /* удаление конкретных символов */
🔶 Приведение булевых значений к стандартному виду
case
when lower(column) in ('1', 'yes', 'true', 'y', 't') then true
when lower(column) in ('0', 'no', 'false', 'n', 'f') then false
else null
end as bool_column
❕Ну что, как тебе формат? Голосуй реактами и комментами, если хочешь больше такого