Способность специалиста по данным извлекать пользу из данных тесно связана с тем, насколько развита инфраструктура хранения и обработки данных компании.
Это означает, что аналитик должен не только уметь строить модели, но и обладать достаточными навыками проектирования данных, чтобы удовлетворять потребности компании и браться за все более амбициозные проекты.
В то же время, несмотря на свою важность, образование в области инженерии данных продолжает оставаться весьма ограниченным.
Мне посчастливилось работать со многими инженерами, которые терпеливо объясняли мне все аспекты науки о данных, но не у всех есть такие способности.
Вот почему я решил написать эту статью — введение в инженерию данных, в которой я расскажу о том, что такое ETL, о разнице между ETL на основе SQL и JVM, о нормализации и секционировании данных и, наконец, мы рассмотрим пример запроса в Airflow.
Инженерия данных
Максим Бошемен, один из разработчиков Airflow, описал инженерию данных следующим образом: «Это область, которую можно рассматривать как смесь бизнес-аналитики и баз данных, которая вводит больше элементов программирования.«Это направление включает в себя специализацию по работе с распределенными системами больших данных, расширенной экосистемой Hadoop и масштабируемыми вычислениями».
Среди многих навыков инженера данных наиболее важным является умение проектировать, создавать и обслуживать хранилища данных.
Отсутствие качественной инфраструктуры хранения данных означает, что любая деятельность, связанная с анализом данных, либо слишком дорога, либо не масштабируема.
ETL: извлечение, преобразование, загрузка
Извлечение, преобразование и загрузка — это три концептуально важных шага, которые определяют, как устроено большинство современных конвейеров данных.Сегодня это базовая модель подготовки необработанных данных к анализу.
Извлекать.
Это шаг, на котором датчики берут входные данные из различных источников (логи пользователей, копию реляционной базы данных, внешний набор данных и т. д.), а затем передают их для последующих преобразований.
Преобразовать.
Это «сердце» любого ETL, этап, на котором мы применяем бизнес-логику и выполняем фильтрацию, группировку и агрегацию для преобразования необработанных данных в набор данных, готовый для анализа.
Эта процедура требует понимания бизнес-задач и базовых знаний в этой области.
Нагрузка.
Наконец, мы загружаем обработанные данные и отправляем их в место конечного использования.
Результирующий набор данных может использоваться конечными пользователями или представлять собой входной поток для другого ETL.
Какой ETL-фреймворк выбрать?
В мире пакетной обработки данных существует несколько платформ с открытым исходным кодом, с которыми вы можете попробовать поиграть.Некоторые из них: Azkaban — менеджер рабочих процессов с открытым исходным кодом от Linkedin, который обеспечивает легкое управление зависимостями в Hadoop, Luigi — фреймворк от Spotify, основанный на Python, и Airflow, также основанный на Python, от Airbnb. У каждой платформы есть свои плюсы и минусы, многие эксперты пытаются их сравнить (см.
При выборе того или иного каркаса важно учитывать следующие характеристики:
Конфигурация.
ETL довольно сложны по своей природе, поэтому важно, как именно пользователь платформы будет их создавать.
Основано ли это на пользовательском интерфейсе или запросы создаются на каком-то языке программирования? Сегодня именно второй метод набирает все большую популярность, поскольку программирование конвейеров делает их более гибкими, позволяя менять любую деталь.
Мониторинг ошибок и оповещения.
Большие и длинные пакетные запросы рано или поздно завершаются ошибкой, даже если в самом задании нет ошибок.
В результате на первый план выходят мониторинг и уведомления об ошибках.
Насколько хорошо платформа визуализирует ход выполнения запроса? Уведомления приходят вовремя? Обратная загрузка данных.
Часто после построения готового конвейера нам нужно вернуться и повторно обработать исторические данные.
В идеале нам не хотелось бы строить два независимых рабочих места: одно для реверса исторических данных, а второе для текущей активности.
Насколько легко выполнить заполнение с помощью этой платформы? Является ли полученное решение масштабируемым и эффективным?
2 парадигмы: SQL против JVM
Как мы выяснили, у компаний есть огромный выбор, какие инструменты использовать для ETL, и для начинающего дата-сайентиста не всегда понятно, какому фреймворку уделить время.Это как раз про меня: в Washington Post Labs очередь заданий выполнялась примитивно, с помощью Cron, в Twitter ETL задания строились в Pig, а сейчас в Airbnb мы пишем конвейеры в Hive через Airflow. Поэтому, прежде чем идти в ту или иную компанию, постарайтесь узнать, как именно в них организован ETL. Упрощенно можно выделить две основные парадигмы: SQL И ETL, ориентированный на JVM. JVM-ориентированный ETL обычно пишется на JVM-ориентированном языке (Java или Scala).
Построение конвейеров данных на таких языках означает определение преобразований данных с помощью пар ключ-значение, но написание пользовательских функций и заданий тестирования становится проще, поскольку для этого не нужно использовать другой язык программирования.
Эта парадигма очень популярна среди инженеров.
SQL-ориентированный ETL чаще всего пишется на SQL, Presto или Hive. Практически все крутится вокруг SQL и таблиц, что очень удобно.
Однако написание пользовательских функций может быть проблематичным, поскольку требует использования другого языка (например, Java или Python).
Этот подход популярен среди специалистов по обработке данных.
Поработав с обеими парадигмами, я все же предпочитаю SQL-ориентированный ETL, поскольку начинающему специалисту по данным гораздо проще выучить SQL, чем Java или Scala (если, конечно, вы с ними уже не знакомы) и сосредоточиться на изучении новички практикуются, а не накладывают это на изучение нового языка.
Моделирование данных, нормализация и звездная схема
В процессе построения качественной аналитической платформы основная цель проектировщика системы — сделать так, чтобы аналитические запросы было легко писать, а различная статистика рассчитывалась эффективно.Для этого прежде всего необходимо определиться модель данных.
В качестве одного из первых шагов в моделировании данных необходимо понять, в какой степени таблицы должны быть нормализованный .
В целом нормализованные таблицы имеют более простые схемы, более стандартизированные данные и устраняют некоторые виды избыточности.
В то же время использование таких таблиц приводит к тому, что установление связей между таблицами требует большей точности и усердия, запросы становятся более сложными (больше JOINов), и необходимо поддерживать больше ETL-заданий.
С другой стороны, гораздо проще писать запросы к денормализованным таблицам, поскольку все измерения и метрики уже связаны.
Однако, учитывая больший размер таблиц, обработка данных становится медленнее («Здесь можно спорить, ведь все зависит от того, как хранятся данные и какие запросы бывают. Можно, например, хранить большие таблицы в Hbase и обращаться к отдельным столбцам, тогда запросы будут быстрыми» — прим.
Из всех моделей данных, которые пытаются найти идеальный баланс между двумя подходами, одна из самых популярных (мы используем ее в Airbnb) — звездная схема .
Эта схема основана на построении нормализованных таблиц (таблиц фактов и таблиц измерений), из которых при необходимости можно получить денормализованные таблицы.
В результате этот дизайн пытается найти баланс между простотой аналитики и сложностью поддержки ETL.
Таблицы фактов и таблицы измерений
Чтобы лучше понять, как создавать денормализованные таблицы из таблиц фактов и таблиц измерений, давайте обсудим роли каждой из них: Таблицы фактов чаще всего содержат данные о транзакциях в определенные моменты времени.Каждая строка в таблице может быть чрезвычайно простой и чаще всего представляет собой одну транзакцию.
В Airbnb есть множество таблиц фактов, в которых хранятся данные по типам транзакций: бронирования, оформления заказа, отмены и т. д. Таблицы измерений содержат медленно меняющиеся атрибуты определенных ключей из таблицы фактов и могут быть присоединены к ней с помощью этих ключей.
Сами атрибуты могут быть организованы в иерархическую структуру.
Например, у Airbnb есть таблицы измерений с указанием пользователей, заказов и рынков, которые помогают нам детально анализировать данные.
Ниже приведен простой пример того, как можно объединить таблицы фактов и таблицы измерений (нормализованные), чтобы ответить на простой вопрос: сколько бронирований было сделано за последнюю неделю на каждом рынке?
SELECT b.dim_market , SUM(a.m_bookings) AS m_bookings FROM ( SELECT id_listing , 1 AS m_bookings , m_a # not used (for illustration only) , m_b # not used (for illustration only) , m_c # not used (for illustration only) FROM fct_bookings WHERE ds BETWEEN '{{ last_sunday }}' AND '{{ this_saturday }}' ) a JOIN ( SELECT id_listing , dim_market , dim_x # not used (for illustration only) , dim_y # not used (for illustration only) , dim_z # not used (for illustration only) FROM dim_listings WHERE ds BETWEEN '{{ latest_ds }}' ) b ON (a.id_listing = b.id_listing) GROUP BY b.dim_market ;
Разделение данных по временной метке
Теперь, когда стоимость хранения данных очень низка, компании могут позволить себе хранить исторические данные в своих хранилищах, а не выбрасывать их.Обратной стороной этой тенденции является то, что по мере накопления данных аналитические запросы становятся неэффективными и медленными.
Наряду с такими принципами SQL, как «фильтровать данные чаще и раньше» и «использовать только те поля, которые нужны», можно выделить еще один, позволяющий повысить эффективность запросов: секционирование данных .
Основная идея секционирования очень проста — вместо того, чтобы хранить данные одним куском, мы делим их на несколько независимых частей.
Все части сохраняют первичный ключ исходной части, поэтому к любым данным можно получить довольно быстрый доступ.
В частности, использование временной метки в качестве ключа для разделения имеет ряд преимуществ.
Во-первых, в хранилище S3 необработанные данные часто сортируются по временным меткам и сохраняются в каталогах, которые также отмечены временными метками.
Во-вторых, обычно пакетное задание ETL занимает около одного дня, то есть для каждого задания каждый день создаются новые разделы данных.
Наконец, многие аналитические запросы включают подсчет количества событий, произошедших за определенный период времени, поэтому здесь пригодится секционирование по времени.
Заполнение исторических данных
Еще одним важным преимуществом использования временной метки в качестве ключа разделения является простота обратного заполнения данных.Если ETL-конвейер уже построен, то он рассчитывает метрики и измерения заранее, а не ретроспективно.
Часто нам хотелось бы взглянуть на существующие тенденции путем расчета измерений в прошлом – этот процесс называется засыпка .
Обратная засыпка настолько распространена, что в Hive есть встроенная функция.
динамическое секционирование для выполнения одних и тех же SQL-запросов на нескольких разделах одновременно.
Проиллюстрируем эту идею на примере: допустим, вам нужно заполнить на дашборде количество бронирований для каждого рынка, начиная с Early_ds и окончание последние_дс .
Одно из возможных решений выглядит примерно так: INSERT OVERWRITE TABLE bookings_summary PARTITION (ds= '{{ earliest_ds }}')
SELECT
dim_market
, SUM(m_bookings) AS m_bookings
FROM
fct_bookings
WHERE
ds = '{{ earliest_ds }}'
GROUP BY
dim_market
;
# after many insertions from '{{ earliest_ds + 1 day }}' to '{{ latest_ds - 1 day }}'
INSERT OVERWRITE TABLE bookings_summary PARTITION (ds= '{{ latest_ds }}')
SELECT
dim_market
, SUM(m_bookings) AS m_bookings
FROM
fct_bookings
WHERE
ds = '{{ latest_ds }}'
GROUP BY
dim_market
;
Такой запрос возможен, но он слишком громоздкий, так как мы выполняем одну и ту же операцию, только на разных разделах.
Используя динамическое секционирование, мы можем упростить все до одного запроса: INSERT OVERWRITE TABLE bookings_summary PARTITION (ds)
SELECT
dim_market
, SUM(m_bookings) AS m_bookings
, ds # For Hive to know we are using dynamic partitions
FROM
fct_bookings
WHERE
ds BETWEEN '{{ earliest_ds }}' AND '{{ latest_ds }}'
GROUP BY
dim_market
, ds
;
Обратите внимание, что мы добавили дс В ВЫБИРАТЬ И ГРУППА ПО выражения, расширил диапазон в операции ГДЕ и изменил синтаксис с PARTITION (ds= '{{ds}}') на PARTITION (ds) .
Прелесть динамического секционирования в том, что мы обернули ГРУППИРОВАТЬ ПО ds вокруг необходимых операций для вставки результатов запроса во все разделы за один раз.
Этот подход очень эффективен и используется во многих конвейерах Airbnb.
Теперь давайте рассмотрим все изученные нами концепции на примере заданий ETL в Airflow.
Направленный ациклический граф (DAG)
Казалось бы, с точки зрения идеи ETL задания очень просты, но на самом деле они зачастую очень сложны и состоят из множества комбинаций операций Extract, Transform и Load. В этом случае может быть очень полезно визуализировать весь поток данных с помощью графа, в котором узел представляет операцию, а стрелка представляет связь между операциями.Учитывая, что каждая операция выполняется один раз, а данные перемещаются дальше по графу, она является направленной и ациклической, отсюда и название.
Одной из особенностей интерфейса Airflow является наличие механизма, позволяющего визуализировать конвейер данных через ДАГ.
Автор конвейера должен определить связи между операциями, чтобы Airflow записывал спецификацию задания ETL в отдельный файл.
Более того, помимо DAG, определяющих порядок запуска операций, в Airflow есть операторы, определяющие, что нужно делать внутри конвейера.
Обычно существует 3 типа операторов, каждый из которых имитирует один из этапов процесса ETL:
- Датчики: открыть поток данных по прошествии определенного времени или когда данные из источника ввода станут доступны (аналогично Extract).
- Операторы: запускать определенные команды (выполнять файл Python, запрос в Hive и т. д.).
Подобно Transform, операторы занимаются преобразованием данных.
- Трансферы: перенести данные из одного места в другое (как на этапе загрузки).
Простой пример
Ниже приведен простой пример того, как объявить файл DAG и определить структуру графа с помощью операторов Airflow, которые мы обсуждали выше: """
A DAG docstring might be a good way to explain at a high level
what problem space the DAG is looking at.
Links to design documents, upstream dependencies etc
are highly recommended.
"""
from datetime import datetime, timedelta
from airflow.models import DAG # Import the DAG class
from airflow.operators.sensors import NamedHivePartitionSensor
from airflow.operators.hive_operator import HiveOperator
### You can import more operators as you see fit!
# from airflow.operators.bash_operator import BashOperator
# from airflow.operators.python_operator import PythonOperator
# setting some default arguments for the DAG
default_args = {
'owner': 'you',
'depends_on_past': False,
'start_date': datetime(2018, 2, 9),
}
# Instantiate the Airflow DAG
dag = DAG(
dag_id='anatomy_of_a_dag',
description="This describes my DAG",
default_args=default_args,
schedule_interval=timedelta(days=1)) # This is a daily DAG.
# Put upstream dependencies in a dictionary
wf_dependencies = {
'wf_upstream_table_1': 'upstream_table_1/ds={{ ds }}',
'wf_upstream_table_2': 'upstream_table_2/ds={{ ds }}',
'wf_upstream_table_3': 'upstream_table_3/ds={{ ds }}',
}
# Define the sensors for upstream dependencies
for wf_task_id, partition_name in wf_dependencies.iteritems():
NamedHivePartitionSensor(
task_id=wf_task_id,
partition_names=[partition_name],
dag=dag
)
# Put the tasks in a list
tasks = [
('hql', 'task_1'),
('hql', 'task_2'),
]
# Define the operators in the list above
for directory, task_name in tasks:
HiveOperator(
task_id=task_name,
hql='{0}/{1}.
hql'.
format(directory, task_name),
dag=dag,
)
# Put the dependencies in a map
deps = {
'task_1': [
'wf_upstream_table_1',
'wf_upstream_table_2',
],
'task_2': [
'wf_upstream_table_1',
'wf_upstream_table_2',
'wf_upstream_table_3',
],
}
# Explicitly define the dependencies in the DAG
for downstream, upstream_list in deps.iteritems():
for upstream in upstream_list:
dag.set_dependency(upstream, downstream)
Когда график построен, вы можете увидеть следующую картину:
Итак, я надеюсь, что в этой статье мне удалось максимально быстро и эффективно погрузить вас в интересную и разнообразную область — Data Engineering. Мы изучили, что такое ETL, преимущества и недостатки различных ETL-платформ.
Затем мы обсудили моделирование данных и, в частности, звездообразную схему, а также рассмотрели различия между таблицами фактов и таблицами измерений.
Наконец, рассмотрев такие понятия, как секционирование и обратное заполнение данных, мы перешли к примеру небольшого задания ETL в Airflow. Теперь вы можете самостоятельно учиться работе с данными, пополняя свою базу знаний.
Увидимся! ———— Роберт отмечает, что в мире недостаточно программ дата-инжиниринга, но мы их проводим, и уже не в первый раз.
Мы начинаем в октябре Инженер данных 3.0 , регистрируйтесь и расширяйте свои профессиональные возможности! Теги: #базы данных #Большие данные #Инженерия данных #Интеллектуальный анализ данных #sql #etl #airflow
-
Статья-Обзор Ноутбука Sony Vaio Vgn-Sz270P
19 Oct, 24 -
Герцспрунг, Эйнар
19 Oct, 24 -
Распространение
19 Oct, 24 -
Проекту Netbsd Исполняется 15 Лет
19 Oct, 24 -
Linux Побеждает Во Время Рецессии
19 Oct, 24 -
«Призрак» В Студии
19 Oct, 24 -
Большие Данные В Райффайзенбанке
19 Oct, 24