267 96 12MB
Russian Pages 635 с. [637] Year 2021
Spark в действии
На сайте издательства www.dmkpress.com приведен исходный код к книге на языках Java, Python и Scala. Для чтения этой книги не требуется какойлибо предварительный опыт работы со Spark, Scala или Hadoop.
«Эта книга открывает инструменты и секреты, которые необходимы для управления инновациями в вашей компании или сообществе». Роб Томас, IBM «Незаменимое, исчерпывающее и подробное руководство. Его должен иметь каждый, кто работает с большими данными и занимается обработкой потоков данных в реальном времени». Анупам Сенгупта, GuardHat, Inc. «Эта книга поможет зажечь искру (spark) любви к занятиям распределенной обработкой данных». Конор Редмонд, InComm Product Control «В настоящее время это самая лучшая книга по этой теме». Маркус Бройер, Materna IPS
Темы, затрагиваемые в книге: • создание приложений Spark на языке Java; • архитектура приложений Spark; • потребление данных из файлов, баз данных, потоков и Elasticsearch; • выполнение запросов к распределенным наборам данных с использованием Spark SQL. Жан-Жорж Перрен – опытный архитектор данных и программного обеспечения. Он первым во Франции был удостоен звания IBM Champion и сохранял это почетное звание непрерывно в течение 12 лет.
ISBN 978-5-97060-879-1
Интернет-магазин: www.dmkpress.com Оптовая продажа: КТК “Галактика” [email protected]
www.дмк.рф
9 785970 608791
Spark в действии
Анализ корпоративных данных начинается с чтения, фильтрации и объединения файлов и потоков из многих источников. Система Spark способна обрабатывать разнообразные объемы информации как признанный лидер в этой области, обеспечивая в 100 раз большую скорость, чем Hadoop. Благодаря поддержке SQL, интуитивно понятному интерфейсу и простому и ясному многоязыковому API вы можете использовать Spark без глубокого изучения новой сложной экосистемы. Эта книга научит вас создавать полноценные и завершенные аналитические приложения. В качестве примера используется полный конвейер обработки данных, поступающих со спутников NASA.
Spark в действии
Жан-Жорж Перрен
Жан-Жорж Перрен
Spark в действии
Covers Apache Spark 3
Spark in Action With examples in Java, Python, and Scala SECOND EDITION J E A N - G E O RG E S P E R R I N Foreword by Rob Thomas
Рассматривается версия Apache Spark 3
Spark в действии С примерами на Java, Python и Scala
Ж А Н - ЖО РЖ П Е Р Р Е Н Вступительное слово Роба Томаса
Москва, 2021
УДК 004.43Spark ББК 32.972 П26
П26
Перрен Ж.-Ж. Spark в действии / пер. с анг. А. В. Снастина. – М.: ДМК Пресс, 2021. – 636 с.: ил. ISBN 978-5-97060-879-1 Обработка больших данных с каждым днем приобретает все большее значение. В этой книге подробно рассматривается организация обработки больших данных с использованием аналитической операционной системы Apache Spark. Тщательно описываются процессы потребления, преобразования и публикации результатов обработки данных; продемонстрированы возможности Apache Spark при работе с разнообразными форматами исходных данных (текст, JSON, XML, СУРБД и многими другими) и при публикации результатов в разнообразных форматах. Особое внимание уделяется обработке потоковых данных, что весьма важно в современных условиях. Подробно рассмотрены организация и архитектура кластера Spark. В приложениях представлена обширная справочная информация, необходимая каждому разработчику, использующему Spark. Книга содержит множество иллюстраций и примеров исходного кода на языке Java с подробными комментариями. Издание предназначено для разработчиков, начинающих осваивать систему Spark.
УДК 004.43Spark ББК 32.972
Original English language edition published by Manning Publications USA, USA. Russian-language edition copyright © 2021 by DMK Press. All rights reserved. Все права защищены. Любая часть этой книги не может быть воспроизведена в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав.
ISBN 978-1-6172-9552-2 (анг.) ISBN 978-5-97060-879-1 (рус.)
© Manning Publications, 2020 © Оформление, издание, перевод, ДМК Пресс, 2021
Оглавление Часть I 1 2 3 4 5 6 Часть II 7 8 9 10 Часть III 11 12 13 14 15
Часть IV 16
17
18
Теория, разбавленная превосходными примерами ............................35 Так что же такое Spark? ..........................................................................36 Архитектура и рабочий процесс ............................................................56 Важнейшая роль фрейма данных ..........................................................72 Природная лень .................................................................................... 112 Создание простого приложения для развертывания ........................ 138 Развертывание простого приложения ................................................ 165 Потребление данных ............................................................................ 190 Потребление данных из файлов .......................................................... 192 Потребление из баз данных ................................................................. 226 Более сложный процесс потребления: поиск источников данных и создание собственных ......................................................... 255 Потребление через структурированные потоки ................................ 288 Преобразование данных ...................................................................... 313 Работа с языком SQL ............................................................................ 314 Преобразование данных ...................................................................... 329 Преобразование документов в целом................................................. 364 Расширенные преобразования с помощью функций, определенных пользователем ............................................................. 378 Агрегирование данных ........................................................................ 396 Продолжаем изучение Spark ................................................................ 424 Кеширование и копирование данных в контрольных точках: улучшение производительности Spark ............................................... 426 Экспорт данных и создание полноценных конвейеров обработки данных ................................................................................ 455 Описание ограничений процесса развертывания: объяснение экосистемы ........................................................................................... 478
Содержание Оглавление ..................................................................................................5 Словарь терминов ...................................................................................15 Вступительное слово ..............................................................................17 Предисловие .............................................................................................19 Благодарности ..........................................................................................21 О чем эта книга ........................................................................................24 Об авторе ...................................................................................................32 Иллюстрация на обложке ......................................................................33
Часть I
1
Теория, разбавленная превосходными примерами................................................................................35
Так что же такое Spark? ............................................................36 1.1 1.2
1.3
Общая картина: что такое Spark и что он делает ...................37
1.1.1 Что такое Spark ....................................................................37 1.1.2 Четыре столпа маны .............................................................40 Как можно использовать Spark ..................................................41 1.2.1 Spark в процессе обработки данных / инженерии данных .......41 1.2.2 Spark в научных исследованиях в области обработки данных ....................................................................................44 Что можно делать с помощью Spark .........................................45 1.3.1 Spark прогнозирует качество пунктов питания Северной Каролины ................................................................46 1.3.2 Spark обеспечивает быструю передачу данных для Lumeris .............................................................................47 1.3.3 Spark анализирует журналы наблюдения за оборудованием CERN .........................................................48 1.3.4 Другие варианты использования ...........................................48
Содержание
1.4
7
Почему вам очень понравится фрейм данных .......................48
1.4.1 Фрейм данных с точки зрения Java ........................................49 1.4.2 Фрейм данных с точки зрения СУРБД ...................................49 1.4.3 Графическое представление фрейма данных.........................50 1.5 Первый пример..............................................................................51 1.5.1 Рекомендуемое программное обеспечение .............................51 1.5.2 Скачивание исходного кода ....................................................52 1.5.3 Запуск первого приложения ...................................................52 1.5.4 Первый исходный код для вас .................................................53 Резюме .......................................................................................................54
2
Архитектура и рабочий процесс ............................................56 2.1 2.2 2.3
Создание собственной мысленной (когнитивной) модели .............................................................................................57 Использование кода Java для создания мысленной (когнитивной) модели..................................................................58 Подробный разбор приложения ................................................61
2.3.1 Установление соединения с ведущим узлом...........................62 2.3.2 Загрузка или потребление содержимого CSV-файла ............63 2.3.3 Преобразование данных .........................................................66 2.3.4 Сохранение работы, сделанной в фрейме данных, в базе данных ..........................................................................68 Резюме .......................................................................................................71
3
Важнейшая роль фрейма данных ...........................................72 3.1
Чрезвычайно важная роль фрейма данных в Spark ..............73
3.1.1 Внутренняя организация фрейма данных .............................74 3.1.2 Неизменяемость – это не клятва .........................................75 3.2 Использование фреймов данных на примерах ......................77 3.2.1 Фрейм данных после простой операции потребления CSV-файла ..............................................................................79 3.2.2 Данные хранятся в разделах..................................................84 3.2.3 Подробнее о схеме...................................................................86 3.2.4 Фрейм данных после потребления формата JSON ...............87 3.2.5 Объединение двух фреймов данных ........................................94 3.3 Фрейм данных как структура Dataset.............................99 3.3.1 Повторное использование простых старых объектов Java (POJO)............................................................................ 100 3.3.2 Создание набора данных из строк ....................................... 101 3.3.3 Преобразование фрейма данных в набор данных и обратно ............................................................................. 103 3.4 Предшественник фрейма данных: RDD ................................. 109 Резюме ..................................................................................................... 110
Содержание
8
4
Природная лень................................................................................ 112 4.1 4.2
4.3
4.4
Пример рациональной лени из реальной жизни................. 113 Пример рациональной лени в Spark ....................................... 114 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5
Рассмотрение результатов преобразований и действий ............................................................................ 115 Процесс преобразования шаг за шагом ................................ 116 Код реализации процесса преобразования/действия .......... 119 Загадка создания 7 миллионов точек данных за 182 мс ...... 123 Загадка, связанная с измерением времени для действий ........................................................................ 125 Сравнение с СУРБД и обычными приложениями ............... 130 4.3.1 Обработка набора данных с коэффициентами рождаемости для подростков ............................................. 130 4.3.2 Анализ различий между обычным приложением и приложением Spark....................................................................... 131
Spark великолепно подходит для приложений, ориентированных на обработку данных ............................... 133 4.5 Catalyst – катализатор приложения ........................................ 133 Резюме ..................................................................................................... 137
5
Создание простого приложения для развертывания ....................................................................... 138 5.1
Пример без операции потребления данных ......................... 139
Вычисление π ........................................................................ 139 Исходный код для вычисления приближенного значения π .... 142 Что такое лямбда-функции в Java ...................................... 148 Приближенное вычисление π с использованием лямбда-функций ................................................................... 150 5.2 Взаимодействие со Spark ........................................................... 152 5.2.1 Локальный режим................................................................. 153 5.2.2 Режим кластера ................................................................... 154 5.2.3 Интерактивный режим Scala и Python ............................... 158 Резюме ..................................................................................................... 163
6
5.1.1 5.1.2 5.1.3 5.1.4
Развертывание простого приложения ............................. 165 6.1
6.2
Подготовка к изучению примера: роль компонент ............ 168 6.1.1 6.1.2 6.1.3
Краткий обзор компонент и взаимодействий между ними .......................................................................... 168 Рекомендации по устранению проблем в архитектуре Spark ..................................................................................... 172 Дополнительная информация для изучения ........................ 173 Создание кластера ...................................................................... 174 6.2.1 Создание собственного кластера ........................................ 174 6.2.2 Настройка среды кластера ................................................. 176
Содержание
6.3
9
Создание приложения для работы в кластере ...................... 179
6.3.1 Создание файла uberJAR для приложения ............................ 180 6.3.2 Создание приложения с использованием Git и Maven .......... 182 6.4 Выполнение приложения в кластере ...................................... 185 6.4.1 Передача файла uberJAR ...................................................... 185 6.4.2 Выполнение приложения ...................................................... 186 6.4.3 Анализ пользовательского интерфейса Spark .................... 187 Резюме ..................................................................................................... 188
Часть II
7
Потребление данных ....................................................... 190
Потребление данных из файлов ............................................ 192 7.1 7.2
Общее поведение парсеров ...................................................... 194 Сложная процедура потребления данных из CSV-файла ................................................................................ 194
7.2.1 Требуемый вывод результата ............................................. 196 7.2.2 Код ........................................................................................ 197 7.3 Потребление CSV-данных с известной схемой .................... 198 7.3.1 Требуемый вывод результата ............................................. 199 7.3.2 Код ........................................................................................ 200 7.4 Потребление данных из JSON-файла...................................... 201 7.4.1 Требуемый вывод результата ............................................. 203 7.4.2 Код ........................................................................................ 204 7.5 Потребление данных из многострочного JSON-файла....... 205 7.5.1 Требуемый вывод результата ............................................. 207 7.5.2 Код ........................................................................................ 207 7.6 Потребление данных из файла XML ....................................... 208 7.6.1 Требуемый вывод результата ............................................. 210 7.6.2 Код ........................................................................................ 211 7.7 Потребление данных из текстового файла............................ 213 7.7.1 Требуемый вывод результата ............................................. 214 7.7.2 Код ........................................................................................ 214 7.8 Форматы файлов для больших данных .................................. 215 7.8.1 Проблема с обычными форматами файлов......................... 215 7.8.2 Avro – формат сериализации на основе схемы .................... 217 7.8.3 ORC – формат хранения данных в столбцах....................... 217 7.8.4 Parquet – еще один формат хранения данных в столбцах .... 218 7.8.5 Сравнение форматов Avro, ORC и Parquet........................... 218 7.9 Потребление данных из файлов Avro, ORC и Parquet ......... 218 7.9.1 Потребление данных в формате Avro ................................. 219 7.9.2 Потребление данных в формате ORC ................................. 221 7.9.3 Потребление данных в формате Parquet ............................ 222 7.9.4 Справочная информация по организации потребления данных в форматах Avro, ORC, Parquet ............................... 224 Резюме ..................................................................................................... 224
Содержание
10
8
9
Потребление из баз данных ..................................................... 226 8.1
Потребление из реляционных баз данных ............................ 228
8.1.1 Контрольный перечень операций при установлении соединения с базой данных .............................................................. 228 8.1.2 Объяснение происхождения данных, используемых в следующих примерах ..................................................................... 229 8.1.3 Требуемый вывод результата ............................................. 231 8.1.4 Код ........................................................................................ 232 8.1.5 Другая версия кода ............................................................... 234 8.2 Роль диалекта ............................................................................... 236 8.2.1 Что такое диалект ............................................................. 236 8.2.2 Диалекты JDBC, предоставляемые в Spark ......................... 237 8.2.3 Создание собственного диалекта ........................................ 237 8.3 Расширенные запросы и процесс потребления ................... 240 8.3.1 Фильтрация с использованием ключевого слова WHERE........ 240 8.3.2 Соединение данных в базе данных ........................................ 243 8.3.3 Выполнение потребления и распределение данных ............. 246 8.3.4 Итоги изучения расширенных функциональных возможностей ................................................................................. 249 8.4 Потребление данных из Elasticsearch ..................................... 249 8.4.1 Поток данных....................................................................... 249 8.4.2 Набор данных о ресторанах Нью-Йорка, извлекаемый Spark ..................................................................................... 250 8.4.3 Исходный код для потребления набора данных о ресторанах из Elasticsearch ............................................... 252 Резюме ..................................................................................................... 253
Более сложный процесс потребления: поиск источников данных и создание собственных................ 255 9.1 9.2
9.3 9.4
9.5 9.6
Что такое источник данных ...................................................... 257 Преимущества прямого соединения с источником данных ........................................................................................... 259
9.2.1 Временные файлы................................................................. 260 9.2.2 Скрипты для улучшения качества данных .......................... 260 9.2.3 Данные по запросу ................................................................ 261 Поиск источников данных на сайте Spark Packages ............ 261 Создание собственного источника данных........................... 261 9.4.1 Обзор примера проекта....................................................... 262 9.4.2 Интерфейс API специализированного источника данных и его параметры ...................................................... 264
Что происходит внутри: создание самого источника данных ........................................................................................... 267 Использование файла регистрации и заявочного класса.............................................................................................. 268
Содержание
9.7
11
Объяснение взаимоотношения между данными и схемой......................................................................................... 270
9.7.1 Источник данных создает отношение ................................ 271 9.7.2 Внутри отношения .............................................................. 274 9.8 Создание схемы из JavaBean ..................................................... 277 9.9 Создание фрейма данных – манипуляции с утилитами .... 280 9.10 Другие классы .............................................................................. 286 Резюме ..................................................................................................... 286
10
Потребление через структурированные потоки ...... 288 10.1 Что такое потоковая обработка................................................ 290 10.2 Создание первого потока данных ........................................... 292
10.2.1 Генерация потока данных .................................................... 293 10.2.2 Потребление записей ........................................................... 296 10.2.3 Считывание записей, а не строк ......................................... 302 10.3 Потребление данных из сетевых потоков ............................. 303 10.4 Работа с несколькими потоками ............................................. 306
10.5 Различия между дискретизированными и структурированными потоками........................................... 311 Резюме ..................................................................................................... 312
Часть III
Преобразование данных ............................................... 313
11
Работа с языком SQL................................................................... 314
12
Преобразование данных ............................................................. 329
11.1 Работа со Spark SQL ..................................................................... 315 11.2 Различия между локальными и глобальными представлениями ........................................................................ 319 11.3 Совместное использование API фрейма данных и Spark SQL .................................................................................... 321 11.4 Не удаляйте (DELETE) данные .................................................... 324 11.5 Рекомендации для дальнейшего изучения SQL ................... 327 Резюме ..................................................................................................... 327
12.1 Что такое преобразование данных ......................................... 330 12.2 Процесс и пример преобразования данных на уровне записи ............................................................................................ 331
12.2.1 Обследование данных для оценки их сложности ................. 333 12.2.2 Отображение данных для создания схемы процесса ........... 335 12.2.3 Написание исходного кода преобразования ......................... 338 12.2.4 Итоговый обзор результата преобразования данных для обеспечения качества обработки ................................. 345 12.2.5 Несколько слов о сортировке ............................................... 347
12
Содержание
12.2.6 Завершение первого процесса преобразования с использованием Spark ........................................................ 347 12.3 Соединение наборов данных.................................................... 348 12.3.1 Более подробно о соединяемых наборах данных .................. 348 12.3.2 Создание списка вузов по округам........................................ 350 12.3.3 Выполнение соединений........................................................ 356 12.4 Выполнение других преобразований ..................................... 362 Резюме ..................................................................................................... 362
13
Преобразование документов в целом................................ 364 13.1 Преобразование документов в целом и их структура ........ 365
13.1.1 Упрощение структуры документа в формате JSON .......... 365 13.1.2 Создание документов с вложенной структурой для передачи и сохранения ................................................... 371 13.2 Секреты статических функций ................................................ 376 13.3 Выполнение других преобразований ..................................... 377 Резюме ..................................................................................................... 377
14
Расширенные преобразования с помощью функций, определенных пользователем ........................... 378 14.1 Расширение функциональности Apache Spark ..................... 379 14.2 Регистрация и вызов UDF .......................................................... 381
14.2.1 Регистрация UDF в Spark ..................................................... 384 14.2.2 Использование UDF совместно с API фрейма данных ......... 385 14.2.3 Использование UDF совместно с SQL .................................. 387 14.2.4 Реализация UDF .................................................................... 388 14.2.5 Написание кода сервиса ....................................................... 390
14.3 Использование UDF для обеспечения высокого уровня качества данных .......................................................................... 392 14.4 Ограничения использования UDF ........................................... 394 Резюме ..................................................................................................... 395
15
Агрегирование данных ................................................................. 396 15.1 Агрегирование данных в Spark ................................................ 397
15.1.1 Краткое описание агрегаций ............................................... 397 15.1.2 Выполнение простых агрегаций с использованием Spark .... 400 15.2 Выполнение агрегаций с оперативными данными ............ 403 15.2.1 Подготовка набора данных.................................................. 403 15.2.2 Агрегация данных для получения более точной информации о школах .......................................................... 408
15.3 Создание специализированных агрегаций с использованием UDAF ....................................................................... 415 Резюме ..................................................................................................... 422
Содержание
Часть IV
16
13
Продолжаем изучение Spark ...................................... 424
Кеширование и копирование данных в контрольных точках: улучшение производительности Spark ..................................................... 426 16.1 Кеширование и копирование данных в контрольных точках могут повысить производительность ....................... 427
16.1.1 Полезность кеширования в Spark ........................................ 429 16.1.2 Изысканная эффективность механизма копирования данных в контрольных точках в Spark ................................ 431 16.1.3 Использование кеширования и копирования данных в контрольных точках ......................................................... 431 16.2 Кеширование на практике ........................................................ 442
16.3 Дополнительные материалы по оптимизации производительности .................................................................. 452 Резюме ..................................................................................................... 453
17
Экспорт данных и создание полноценных конвейеров обработки данных............................................... 455 17.1 Экспорт данных ........................................................................... 456 17.1.1 Создание конвейера с наборами данных NASA .................... 456 17.1.2. Преобразование столбцов в метки времени datetime ......... 459 17.1.3 Преобразование процентов степени достоверности в уровень достоверности ..................................................... 461 17.1.4 Экспорт данных ................................................................... 462 17.1.5 Экспорт данных: что происходит в действительности ............................................................ 465 17.2 Delta Lake: удобная база данных прямо в системе .............. 466 17.2.1 Объяснение, почему необходима база данных ...................... 467 17.2.2 Использование Delta Lake в конвейере обработки данных .... 468 17.2.3 Потребление данных из Delta Lake ...................................... 473 17.3 Доступ к сервисам облачного хранилища из Spark ............. 475 Резюме ..................................................................................................... 477
18
Описание ограничений процесса развертывания: объяснение экосистемы .............................................................. 478
18.1 Управление ресурсами с использованием YARN, Mesos и Kubernetes ...................................................................... 479
18.1.1 Встроенный автономный режим управления ресурсами ..... 480 18.1.2 YARN управляет ресурсами в среде Hadoop ........................ 481 18.1.3 Mesos – автономный диспетчер ресурсов ........................... 483 18.1.4 Kubernetes управляет оркестровкой контейнеров ............. 484 18.1.5 Правильный выбор диспетчера ресурсов ............................. 486
Содержание
14
18.2 Совместное использование файлов с помощью Spark ....... 486
18.2.1 Доступ к данным, содержащимся в файлах......................... 487 18.2.2 Совместное использование файлов с помощью распределенных файловых систем....................................... 488 18.2.3 Доступ к файлам на совместно используемых накопителях или на файловом сервере ............................... 490 18.2.4 Работа с сервисами совместного использования файлов для распределения файлов ....................................... 491 18.2.5 Другие варианты обеспечения доступа к файлам в Spark .................................................................................. 492 18.2.6 Гибридное решение совместного использования файлов в Spark .................................................................................. 492 18.3 Уверенность в безопасности приложения Spark .................. 492 18.3.1 Безопасность сетевых компонентов инфраструктуры ..... 493 18.3.2 Безопасность при использовании диска Spark ..................... 494 Резюме ..................................................................................................... 495
Приложение A Приложение B Приложение C Приложение D Приложение E Приложение F Приложение G Приложение H Приложение I Приложение J Приложение К Приложение L Приложение М Приложение N Приложение О Приложение P Приложение Q Приложение R
Установка Eclipse ................................................................... 496 Установка Maven .................................................................... 502 Установка Git .......................................................................... 506 Загрузка исходного кода и начало работы в Eclipse ...... 508 Хронология корпоративных данных ................................ 514 Справочная информация по реляционным базам данных ......................................................................... 519 Статические функции упрощают преобразования ....... 524 Краткий справочник по Maven .......................................... 533 Справочник по преобразованиям и действиям ............. 538 Немного Scala ......................................................................... 548 Установка Spark в реальной эксплуатационной среде и несколько рекомендаций ..................................... 550 Справочник по операциям потребления ......................... 563 Справочник по соединениям ............................................. 574 Установка Elasticsearch и пример набора данных ......... 586 Генерация потоковых данных ............................................ 592 Справочник по обработке потоковых данных ............... 597 Справочник по экспорту данных....................................... 608 Где искать помощь при затруднениях ............................. 616 Предметный указатель ........................................................ 621
Словарь терминов Краткое описание терминов Spark, используемых в процессе развертывания. Термин на английском языке Application
Термин на русском языке Приложение
Application JAR
JAR-приложение
Cluster manager
Диспетчер кластера
Deploy mode
Режим развертывания
Driver program
Программа-драйвер
Executor
Исполнитель
Job
Задание
Stage
Этап
Task
Задача
Worker node
Рабочий узел
Определение Программа, которая создается в рабочей среде Spark и для функционирования в Spark. Состоит из программы-драйвера и исполнителей в кластере Архивный файл Java (JAR), содержащий приложение Spark. Это может быть файл uber-JAR, включающий все зависимости Внешний сервис для распределения ресурсов в кластере. Возможно использование встроенного в Spark диспетчера кластера Определяет, где запускается и работает процесс драйвера. В режиме кластера (cluster mode) фреймворк запускает драйвер внутри кластера. В режиме клиента (client mode) ведомый (подчиненный) запускает драйвер за пределами кластера. Можно определить, в каком режиме вы находитесь, выполнив метод deployMode(). Метод возвращает свойство, защищенное от изменения (только для чтения) Процесс, выполняющий основную функцию main() приложения и создающий контекст SparkContext. Все начинается именно здесь Процесс, запускаемый для приложения на рабочем узле. Исполнитель выполняет задачи и сохраняет промежуточные данные в памяти или на диске. У каждого приложения имеются собственные исполнители Параллельное вычисление (выполнение), состоящее из нескольких задач, которые порождаются в ответ на некоторое действие Spark (например, save() или collect(), подробнее см. приложение I) Каждое задание разделяется на более мелкие наборы задач, называемые этапами, зависящими друг от друга (подобно этапам отображения и сокращения в MapReduce) Минимальная единица работы, которая передается одному исполнителю Любой узел, который может выполнять код приложения в кластере
Словарь терминов
16
Процессы и ресурсы приложения
Задание: параллельные задачи, запускаемые после вызова какого-либо действия
Задания разделяются на этапы Доступ к программе-драйверу возможен в соответствующем режиме развертывания
Код конкретного приложения в пакете JAR
Узлы
Вступительное слово Аналитическая операционная система В ХХ веке масштабы деятельности в деловой сфере значительно укрупнились благодаря глобальному расширению и распространению. Любая компания, выполняющая бизнес-операции по всему миру, получила вытекающее из этого преимущество в стоимости и степени распространения, что привело к появлению более конкурентоспособной продукции. Предприятия розничной торговли с глобальной сетью магазинов получили преимущество в распространении товаров, несравнимое с деятельностью более мелких компаний. Результаты этого глобального укрупнения определили преимущества в конкуренции на несколько десятилетий вперед. Всю ситуацию в целом изменил интернет. В настоящее время существует три главных результата глобального укрупнения: сеть – замкнутость, управляемая надежной сетью (Facebook, Twitter, Etsy и т. д.); экономика глобального укрупнения – более низкая цена единицы товара, управляемая объемом (Apple, TSMC и т. д.); данные – всеобъемлющее машинное обучение и интуиция на основе динамически изменяющихся совокупностей данных. В книге Big Data Revolution (Wiley, 2015 г.) я исследовал несколько компаний, которые извлекали реальную выгоду из данных в результате глобального укрупнения бизнес-деятельности. Но сейчас, в 2019 году, большие данные все еще остаются в основном неисследованной областью в организациях по всему миру. Spark – аналитическая операционная система – представляет собой средство, способное изменить существующее положение. Spark стал инструментом, изменившим инновационную политику компании IBM. Spark – это аналитическая операционная система, обеспечивающая стандартизацию и унификацию источников данных и средства доступа к данным. Стандартизированная программная мо-
18
Вступительное слово
дель Spark делает эту систему самым лучшим вариантом выбора для разработчиков, создающих приложения анализа огромных объемов данных. Spark сокращает время и снижает сложность создания аналитических рабочих потоков, позволяя разработчикам сосредоточиться на задачах машинного обучения и создания экосистемы на основе Spark. Мы наблюдали ранее и видим сейчас, как проект с открытым исходным кодом быстро становится источником инноваций в широком масштабе. Эта книга погружает вас в мир Spark. В ней рассматривается мощь этой технологии и гибкость ее экосистемы, а также практические приложения Spark для работы в конкретной современной компании. Вне зависимости от того, являетесь ли вы инженером по обработке данных, научным исследователем в области обработки данных, разработчиком прикладных программ или инженером поддержки ИТ-операций, эта книга расскажет об инструментальных средствах и откроет секреты, которые вы должны знать, чтобы управлять инновациями в своей компании или сообществе. Наша стратегия в IBM – создание собственных проектов на основе и с использованием успешных открытых платформ, но эти проекты должны быть значительными и должны выделяться на общем фоне. Spark является именно такой платформой. В IBM можно найти множество примеров применения этой стратегии, и вы получите такой же результат в своей компании, если выберете этот путь. Spark можно считать инновацией – это аналитическая операционная система, в которой будут успешно развиваться новые решения, устраняющие сдерживающий фактор обработки больших данных. Кроме того, Spark – это сообщество высококвалифицированных ученых и аналитиков в области обработки данных, хорошо знающих Spark, которые могут быстро превратить любые сегодняшние задачи в завтрашние решения. Spark представляет собой один из самых быстро развивающихся проектов с открытым исходным кодом в истории ИТ. Присоединяйтесь к этому движению. – Роб Томас (Rob Thomas), первый вице-президент, подразделение Cloud and Data Platform, IBM
Предисловие Не думаю, чтобы для Apache Spark требовалось какое-то предварительное представление. Если вы читаете эти строки, то, вероятнее всего, уже кое-что знаете о теме этой книги: инженерии данных и науки о данных, применяемой в крупных масштабах с использованием распределенной обработки. Но Spark – это нечто большее, и об этом вы скоро узнаете, прочитав вступительное слово Роба Томаса и главу 1. Как Обеликс упал в котел с магическим зельем1, я «упал в котел» Spark в 2015 году. В то время я работал во французской компании, производящей аппаратные компоненты для компьютеров, где участвовал в проектировании высокопроизводительных систем для анализа данных. Вполне естественно, первое впечатление от Spark было скептическим. Затем я начал постоянно работать со Spark и понял, что результат зависит от самого пользователя. Первоначальный скептицизм превратился в настоящее глубокое увлечение превосходным инструментом, который позволяет обрабатывать данные чрезвычайно простым способом, – это мое искреннее убеждение. Я начал работу над несколькими проектами с использованием Spark, и это позволило мне выступить с сообщениями на Spark Summit, IBM Think, а также сблизиться с инициативами All Things Open, Open Source 101. Кроме того, через местную пользовательскую группу Spark я принял участие в анимации региона Роли-Дурэм в Северной Каролине. Это позволило мне встретиться с замечательными людьми и наблюдать за многочисленными проектами, связанными со Spark. В результате я увлекся Spark еще больше. В этой книге я попытался поделиться с вами своим увлечением. 1
Обеликс (Obelix) – известный персонаж комиксов и мультфильмов. Обеликс – неизменный спутник Астерикса (Asterix). Когда галл Астерикс выпивает магическое зелье, он получает суперсилу, которая помогает ему постоянно побеждать римлян (и пиратов). В раннем детстве Обеликс упал в котел, в котором варилось магическое зелье, воздействие которого на Обеликса стало постоянным. В Европе комиксы (и мультфильмы) про Астерикса (и Обеликса) весьма популярны. Больше информации см. на www.asterix.com/en/.
Предисловие
20
Примеры (или домашние задания) в этой книге основаны на использовании языка Java, но в репозитории книги содержится также код на языках Scala и Python. Сразу после выпуска версии Spark 3.0 сотрудники издательства Manning и я решили убедиться в том, что книга соответствует самым свежим версиям, а не отстает от действительности. Как вы могли догадаться, мне очень нравятся комиксы. Я вырос на комиксах. Мне нравится такой способ передачи информации, в чем вы можете убедиться сами, читая эту книгу. Это не книжка комиксов, но около 200 иллюстраций в ней должны помочь вам понять великолепный инструмент, который называется Apache Spark. Спутником Астерикса является Обеликс, точно так же и у книги «Spark в действии» (второе издание) есть спутник – постоянные средства поддержки, которые можно загрузить бесплатно из раздела ресурсов сайта издательства Manning по быстрой ссылке: http://jgp.net/sia. Эти средства поддержки содержат справочную информацию о статических функциях Spark и в итоге должны превратиться в более полезные справочные ресурсы. Неважно, понравится вам книга или нет, в любом случае отправьте мне сообщение в твиттер на @jgperrin. Если книга понравилась, напишите отзыв на Amazon. Если книга не понравилась, то, как говорят при бракосочетании, (скажите сейчас) или храните молчание вечно. И все же я надеюсь, что книга вам понравится. Alea iacta est – Жребий брошен1.
1
По-английски это высказывание звучит так: «The die is cast». Эту фразу приписывают Юлию Цезарю (заклятому врагу Астерикса), так как именно Цезарь перевел свою армию через Рубикон: событие произошло, и отменить его невозможно – как в случае, когда эта книга вышла из печати и стала доступна читателям.
Благодарности В этом разделе я выражаю благодарность всем, кто помог мне в работе над этой книгой. Возможно, в этом разделе я забыл упомянуть некоторых людей, и если кто-то не обнаружил здесь своего имени, то я очень сожалею об этом. Искренне сожалею. Эта книга потребовала огромных усилий, и работа над ней в одиночку, вероятнее всего, была бы оценена в две или три звезды на Amazon вместо пятизвездочного рейтинга, который мы с вами получим очень скоро (это награда и благодарность за труд!). Я хотел бы начать с благодарности тем рабочим группам, которые доверили мне этот проект, начиная с Zaloni (Анупам Ракшит (Anupam Rakshit) и Туфейл Хан (Tufail Khan)), Lumeris (Йон Фарн (Jon Farn), Сурья Кодуру (Surya Koduru), Ноэль Фостер (Noel Foster), Дивья Пенметса (Divya Penmetsa), Срини Гаддам (Srini Gaddam) и Брайс Татт (Bryce Tutt); всем, кто почти вслепую следовал за мной в массовом движении Spark, всем людям из Veracity Solutions и моей новой команде в Advance Auto Parts. Спасибо Мэри Паркер (Mary Parker) из отдела статистики (Department of Statistics) Техасского университета (University of Texas) в Остине (Austin) и Кристиане Страччиалана Парада (Cristiana Straccialana Parada). Их вклад помог уточнить и сделать более ясным содержимое некоторых разделов. Я хочу поблагодарить все сообщество в целом, в том числе Джима Хьюджеса (Jim Hughes), Майкла Бен-Давида (Michael Ben-David), Марселя-Яна Крейгсмана (Marcel-Jan Krijgsman), Жана-Франсуа Морена (JeanFrancois Morin) и всех неизвестных участников, присылавших запросы на включение изменений в репозиторий GitHub. Также хочу выразить искреннюю благодарность сотрудникам Databricks, IBM, Netflix, Uber, Intel, Apple, Alluxio, Oracle, Microsoft, Cloudera, NVIDIA, Facebook, Google, Alibaba, многочисленных университетов и всем, кто сделал Spark таким, какой он есть. В частности, спасибо за работу, вдохновение и поддержку Холдену Карау (Holden Karau), Яцеку Ласковски (Jacek Laskowski), Шону Оуэну (Sean Owen), Матею Захариа (Matei Zaharia) и Жюлю Дамжи (Jules Damji).
22
Благодарности
Во время работы над этим проектом я участвовал в нескольких подкастах. Благодарю Тобиаса Мейси (Tobias Macey) за подкаст «Data Engineering Podcast» (http://mng.bz/WPjX), Эла Мартина (Al Martin) из IBM за подкаст «Making Data Simple» (http://mng.bz/8p7g) и за подкаст «Roaring Elephant» Джона Масскелейна (Jhon Masschelein) и Дэйва Рассела (Dave Russell) (http://mng.bz/EdRr). В качестве члена команды IBM я был счастлив работать со многими сотрудниками IBM на протяжении всего этого проекта. Они помогали прямо, косвенно или оказывали вдохновляющее воздействие: Роб Томас Rob Thomas (мы должны работать вместе и в дальнейшем), Мариус Чиортеа (Marius Ciortea), Алберт Мартин (Albert Martin) (он, помимо всего прочего, выпускает великолепный подкаст «Make Data Simple»), Стив Мур (Steve Moore), Сурав Мазумдер (Sourav Mazumder), Стейси Ронэхэн (Stacey Ronaghan), Мей-Мей Фу (Mei-Mei Fu), Виджай Боммиреддипалли (Vijay Bommireddipalli) (сохраняй присущее тебе равновесие на всех этих холмах Сан-Франциско!), Сунита Камбампати (Sunitha Kambhampati), Сахдев Зала (Sahdev Zala) и мой брат Стюарт Лайтел (Stuart Litel). Хочу поблагодарить сотрудников издательства Manning, которые приняли в работу этот сумасшедший проект. Как в хороших кинофильмах, перечисляю «в порядке их появления»: рецензент издательства Майкл Стивенс (Michael Stephens), издатель Марьян Бэйс (Marjan Bace), редакторы-консультанты Марина Майклз (Marina Michaels) и Тони Арритола (Toni Arritola); производственный персонал: Ирин Туохи (Erin Twohey), Ребекка Райнхарт (Rebecca Rinehart), Берт Бейтс (Bert Bates), Кэндэс Джиллхулли (Candace Gillhoolley), Радмила Эрцеговац (Radmila Ercegovac), Алекс Драгосавлевич (Aleks Dragosavljevic), Матко Хрватин (Matko Hrvatin), Кристофер Кауфманн (Christopher Kaufmann), Ана Ромак (Ana Romac), Шерил Вайсман (Cheryl Weisman), Лори Уэйдерт (Lori Weidert), Шэрон Уилки (Sharon Wilkey) и Мелоди Долаб (Melody Dolab). Также хочу выразить признательность и поблагодарить всех рецензентов издательства Manning. Это Анупам Сенгупта (Anupam Sengupta), Арун Лаккакулам (Arun Lakkakulam), Кристиан Кройтцер-Бек (Christian Kreutzer-Beck), Кристофер Карделл (Christopher Kardell), Конор Редмонд (Conor Redmond), Эзра Шрёдер (Ezra Schroeder), Габор Ласло Хайба (Gábor László Hajba), Гэри А. Стаффорд (Gary A. Stafford), Джордж Томас (George Thomas), Джулиано Араухо Бертоти (Giuliano Araujo Bertoti), Игор Франка (Igor Franca), Игор Карп (Igor Karp), Йерун Бенкхейсен (Jeroen Benckhuijsen), Хуан Руфес (Juan Rufes), Келвин Джонсон (Kelvin Johnson), Келвин Роулз (Kelvin Rawls), Марио-Леандер Раймер (Mario-Leander Reimer), Маркус Бройер (Markus Breuer), Массимо Далла Ровере (Massimo Dalla Rovere), Паван Мадхира (Pavan Madhira), Самбаран Хазра (Sambaran Hazra), Шоба Айвер (Shobha Iyer), Убальдо Пескаторе (Ubaldo Pescatore), Виктор Дюран (Victor Durán) и Уильям И. Уилер (William E. Wheeler). С помощью всей этой компании удалось написать (надеюсь) хорошую книгу. Также хочу поблагодарить Петара Зечевича (Petar Zečević) и Марко Банаси (Marco Banaći), которые написали первую редакцию этой книги. Спасибо Томасу Локни (Thomas Lockney) за подробную техническую
Благодарности
23
рецензию, а также Рамбабу Поса (Rambabu Posa) за включение исходного кода в книгу. Спасибо Йону Риу (Jon Rioux) (merci, Йонатан!) за первоначальный вариант проекта PySpark in Action. Йон подал идею «создания группы Spark в издательстве Manning». И еще раз спасибо Марине. Марина (Marina Michaels) была моим редактором-консультантом в течение большей части времени работы над книгой. Она всегда была рядом, когда я выдавал предварительные версии, когда нужны были ее советы, она была строга со мной (да, твой контроль никогда не ослабевал!), но ее участие было весьма важным в этом проекте. Я всегда буду помнить наши долгие споры об этой книге (вне зависимости от того, существовали или нет предлоги для разговоров о чем-то еще). Я буду скучать по тебе, старшая сестра (до того момента, когда начнется работа над другой книгой). Наконец, хочу сказать спасибо своим родителям, которые поддерживали меня больше, чем я того заслуживал, а также тем, кому я посвятил эту книгу: моей жене Лиз, которая помогала всем, чем могла, на любом уровне, в том числе и в достижении взаимопонимания с редакторами, и нашим детям Пьеру-Николя, Джеку, Натаниелю и Руби, у которых я украл так много времени, работая над этой книгой.
О чем эта книга Когда я начинал работу над этим проектом, который стал книгой «Spark в действии», второе издание, моими целями были: помощь сообществу Java в использовании Apache Spark с наглядной демонстрации того, что нет необходимости дополнительно изучать языки Scala и/или Python; описание главных концепций, лежащих в основе Apache Spark, инженерии (больших) данных и науке о данных, требующих только знаний о реляционных базах данных и основ языка SQL, и ничего больше; тщательное разъяснение того, что Spark – это операционная система, специально предназначенная для распределенных вычислений и анализа. Я верю в метод обучения по любой теме из области информационных технологий с использованием большого количества примеров. Примеры в этой книге являются чрезвычайно важной частью процесса обучения. Я создавал примеры так, чтобы они были как можно ближе к ситуациям, возникающим в настоящей профессиональной деятельности. Предлагаемые здесь наборы данных взяты из реальных ситуаций, со всеми присущими им качественными недостатками. Это не идеализированные учебные наборы данных, которые «работают всегда». Именно поэтому, объединяя примеры и такие наборы данных, вы будете работать и учиться более практическим способом по сравнению со «стерилизованным» подходом к обучению. Я называю эти примеры лабораторными работами (labs) с надеждой, что они окажутся интересными для вас и вы захотите поэкспериментировать с ними. В книге очень много иллюстраций. Основываясь на широко известном высказывании «Рисунок заменяет тысячу слов», я избавил вас от чтения 183 000 дополнительных слов.
Для кого предназначена эта книга Трудно связать название профессии с названием книги, поэтому если ваша профессия называется инженер по обработке данных, ученый-ис-
О чем эта книга
25
следователь в области обработки данных, инженер программного обеспечения или архитектор программного обеспечения/данных, то книга определенно подходит вам. Если вы архитектор корпоративных приложений, ну тогда, вероятно, вам все это известно, ведь архитектор корпоративных приложений знает все обо всем, не так ли? А если говорить более серьезно, эта книга будет полезной, если вы хотите получить больше знаний по любой из следующих тем. Это: использование Apache Spark для создания конвейеров данных и их анализа: потребление (ingestion), преобразование и экспортирование/публикация; использование Spark без необходимости изучения Scala или Hadoop: изучение Spark с Java; понимание различий между реляционной базой данных и Spark; главные концепции, заложенные в основу больших данных, включая основные компоненты Hadoop, которые можно встретить в рабочей среде Spark; позиционирование Spark в корпоративной архитектуре; использование имеющихся навыков и умений по работе с Java и СУРБД в среде больших данных; понимание API фрейма данных (dataframe); объединение реляционных баз данных с процедурами потребления данных в Spark; сбор и объединение данных из потоков; понимание развития конкретной области промышленности и причин полного соответствия Spark этому процессу; понимание и практическое использование центральной роли фрейма данных; знание того, что представляют собой устойчивые распределенные наборы данных (resilient distributed datasets – RDD) и почему их не следует использовать (в дальнейшем); понимание процесса взаимодействия с рабочей средой Spark; понимание различных компонент Spark: драйвер, исполнители, ведущий узел, рабочие узлы, Catalyst, Tungsten; изучение роли ключевых технологий, производных от Hadoop, таких как YARN или HDFS; понимание роли диспетчера ресурсов, например YARN, Mesos и встроенного диспетчера; потребление данных из различных файлов в пакетном режиме и из потоков; использование SQL совместно со Spark; работа со статическими функциями, предоставляемыми Spark; понимание, что такое неизменяемость (immutability) и почему она так важна; расширение Spark с помощью функций, определяемых пользователем (UDF), в языке Java; расширение Spark с помощью новых источников данных;
О чем эта книга
26
линеаризация данных из формата JSON, чтобы можно было использовать язык SQL; выполнение агрегаций и объединений в фреймах данных; расширение агрегации с помощью функций агрегации, определяемых пользователем (UDAF); понимание различий между кешированием и механизмом копирования данных в контрольных точках (checkpointing) и увеличение производительности конкретных приложений Spark; экспорт данных в файлы и базы данных; понимание процесса развертывания в средах AWS, Azure, IBM Cloud, GCP и в собственных локальных кластерах; потребление данных из файлов с форматами CSV, XML, JSON, текст, Parquet, ORC и Avro; расширение источников данных с примером: как потребляются метаданные фотографий с использованием EXIF и сосредоточением внимания на прикладном интерфейсе Data Source API v1; использование Delta Lake совместно со Spark при создании конвейеров.
Чему вы научитесь, читая эту книгу Цель этой книги – научить вас практическому использованию Spark в конкретных приложениях или созданию приложений специально для Spark. Эта книга предназначена для инженеров по обработке данных и для инженеров программного обеспечения Java. Когда я начинал изучать Spark, все программное обеспечение было написано на Scala, почти вся документация находилась на официальном сайте проекта, а вопросы по Spark появлялись чрезвычайно редко. В документации утверждалось, что для Spark имеется Java API, но подробных развернутых примеров было совсем немного. В то время мои соратники находились в замешательстве, вызванном необходимостью изучения Spark и Scala, а наше руководство требовало результатов. Члены моей группы тогда стали основным стимулом для написания этой книги. Предполагается, что читатель обладает основами знаний о языке Java и о СУРБД (о системах управления реляционными базами данных). Во всех примерах я использовал версию Java 8, хотя уже существует версия Java 11. Для чтения этой книги не нужны какие-либо знания о Hadoop, но, поскольку вам все же потребуются некоторые компоненты Hadoop (лишь немногие), здесь они рассматриваются. Если вы уже знаете Hadoop, то книга поможет освежить эти знания. Нет необходимости в знании языка Scala, так как эта книга о Spark и Java. Когда я был ребенком (должен признать, и сейчас тоже), то читал много французских комиксов (bandes dessinées), это нечто среднее между обычными комиксами и романом в комиксах. Поэтому мне очень нравятся иллюстрации, и я включил огромное количество иллюстраций в эту книгу. На рис. 1 показана обычная для этой книги графическая схе-
О чем эта книга
27
ма, демонстрирующая несколько компонент, значков, условных обозначений и описаний. Компоненты – это простые квадраты, иногда прямоугольники. В верхнем правом углу имеется «соединительный элемент в стиле языка UML», который можно видеть в некоторых классических архитектурных диаграммах
У файлов нестандартный верхний правый угол, похожий на скрепку для бумажных документов
Стрелки обозначают потоки, а не зависимости, как в классических архитектурных диаграммах
Потоковая компонента использует поток данных, обозначенный тремя небольшими кружками
Рис. 1 книге
Легенда (описание) всегда выделяется полужирным шрифтом и снабжена кривой линией со стрелкой, указывающей на описываемый объект
Группы компонент объединяются внутри прямоугольников с пунктирными границами. Если возникает неоднозначность, к компонентам Spark обычно добавляется логотип Spark
Я исключил изображение цилиндра из обозначения баз данных. Обозначения баз данных эволюционировали из бессмысленных (в наши дни) цилиндров в прямоугольник с характерным клинышком
Графические элементы и описания, используемые на иллюстрациях в этой
Как организована книга Эта книга разделена на четыре части и 18 приложений. Часть I предлагает основополагающую информацию о Spark. Вы будете изучать теорию и общие концепции, но не спешите впадать в отчаяние (пока еще рано) – здесь представлено множество примеров и графических схем. Эта часть читается почти как книжка комиксов. Часть I содержит следующие главы: глава 1 – общее введение с простым примером. Вы узнаете, почему Spark представляет собой распределенную аналитическую операционную систему; глава 2 – подробное описание простого процесса Spark; глава 3 – объяснение великолепных свойств фрейма данных, который объединяет API и возможности сохранения данных Spark; глава 4 – вознесение хвалы лени (ленивым, или отложенным, вычислениям), сравнение Spark и СУРБД, а также необходимая общая информация о направленном ациклическом графе (НАГ); главы 5 и 6 взаимосвязаны – вы напишете небольшое приложение, создадите кластер и развернете это приложение. В главе 5 описано
О чем эта книга
28
создание небольшого приложения, а в главе 6 рассматривается его развертывание. В части 2 начинается разделение практических и прагматических примеров, демонстрирующих потребление данных. Потребление (ingestion)1 – это процесс переноса данных в Spark. Это несложный процесс, но для него существует огромное количество возможностей и комбинаций. Часть II содержит следующие главы: глава 7 – описание процесса потребления данных из файлов: CSV, текст, JSON, XML, Avro, ORC и Parquet. Для каждого формата файла приводится отдельный пример; глава 8 – рассматривается потребление из баз данных: данные берутся из реляционных баз данных и других хранилищ данных; глава 9 – потребление из источников данных, устанавливаемых пользователем; глава 10 – обработка потоковых данных. В части 3 описано преобразование данных: я назвал бы это «поднятием тяжелых данных». Рассматривается качество данных, их преобразование и публикация обработанных данных. Эта самая большая часть книги рассказывает об использовании фрейма данных в совокупности с языком SQL, а также с собственным прикладным интерфейсом API, агрегатами, кешированием и расширением Spark с помощью функций, определяемых пользователем (UDF): глава 11 – описание широко известного языка запросов SQL; глава 12 – рассматривается выполнение преобразований; глава 13 – расширение преобразований до уровня всего документа в целом. В этой главе также описываются статические функции, которые являются одним из многих замечательных инструментов Spark; глава 14 – расширение Spark с помощью функций, определяемых пользователем (UDF); агрегаты также представляют собой широко известную концепцию баз данных и могут оказаться весьма важными для анализа. В главе 15 рассматриваются агрегаты, в том числе включенные в Spark и специализированные агрегаты. Заключительная часть IV приближает читателя к реальной производственной среде и рассматривает более продвинутые темы. Вы узнаете о распределении данных в кластере, об экспорте данных, об ограничениях процесса развертывания (включая развертывание в облаке) и об оптимизации: глава 16 – описание методик оптимизации: кеширование и механизм копирования данных в контрольных точках; глава 17 – экспорт данных в файлы и базы данных. В этой главе так1
Дословный перевод термина «ingestion» – потребление, прием пищи, поглощение, всасывание. – Прим. перев.
О чем эта книга
29
же описано использование Data Lake, базы данных, размещаемой рядом с ядром Spark; глава 18 – подробная справочная информация об архитектурах и методах обеспечения безопасности, необходимых для развертывания. Эта глава в меньшей степени связана с практикой, но содержит весьма важную информацию. Приложения не так важны, но содержат большой объем информации: об установке, об устранении возникающих проблем и ошибок, а также о создании рабочего контекста. Почти все приложения содержат справочную информацию по Apache Spark в контексте Java.
Исходный код примеров Как уже было отмечено ранее, каждая глава (за исключением 6 и 18) содержит лабораторные работы, в которых объединен исходный код и данные. Исходный код приводится в пронумерованных листингах и в отдельных строках обычного текста. В обоих случаях исходный код выделяется моноширинным шрифтом, как здесь, чтобы отделить его от обычного текста. Иногда некоторые фрагменты кода кроме моноширинного обозначаются еще и полужирным шрифтом, чтобы выделить ту часть кода, которая является более важной в блоке кода. Весь исходный код свободно и бесплатно доступен в репозитории GitHub под лицензией Apache 2.0. Данные могут быть защищены различными лицензиями. Для каждой главы создан собственный отдельный репозиторий GitHub: для главы 1 – https://github.com/jgperrin/net. jgp.books.spark.ch01, для главы 15 – https://github.com/jgperrin/net.jgp. books.spark.ch15 и т. д. Два исключения:
в главе 6 используется исходный код из главы 5; в главе 18, где подробно рассматривается процесс развертывания, нет исходного кода.
Так как инструментальные средства управления исходным кодом позволяют создавать ответвления версий, главная ветвь содержит исходный код самой последней готовой к реальному использованию версии, тогда как каждый репозиторий содержит ветви для специализированных или пробных версий, когда это необходимо. Лабораторные работы пронумерованы трехзначными числами, начиная со 100. Предлагается два типа лабораторных работ: лабораторные работы, описанные в книге, и дополнительные лабораторные работы, доступные в режиме онлайн: лабораторные работы, описанные в книге, нумеруются по разделам соответствующей главы. Таким образом, лабораторная работа #200 главы 12 находится в главе 12 в разделе 2. А лабораторная работа #100 главы 17 описывается в первом разделе главы 17; лабораторные работы, не описанные в книге, нумеруются числами, начинающимися с цифры 9, т. е. 900, 910 и т. д. Группа с номерами, начиная с 900, постоянно увеличивается: я добавляю в нее новые
О чем эта книга
30
лабораторные работы. Нумерация этих лабораторных работ не является непрерывной – как нумерация строк кода Basic. В репозиториях GitHub вы найдете исходный код на Python, Scala и Java (кроме тех случаев, когда код на каком-либо из этих языков неприменим). Но в книге используется только Java для сохранения ясности. Во многих случаях исходный код, приведенный в книге, требует переформатирования: в код добавлены разрывы строк и изменено выравнивание строк для соответствующего размещения исходного кода на доступном пространстве страницы книги. В редких случаях, когда даже вышеописанных мер недостаточно, в листинги включены маркеры продолжения строки (➥). Кроме того, комментарии к исходному коду были удалены из листингов в тех случаях, когда код описывается в тексте. Во многих листингах к исходному коду приложены примечания, объясняющие важные концепции.
Форум для обсуждения книги liveBook Приобретение книги «Spark в действии» дает право на свободный доступ на частный веб-форум издательства Manning Publications, где вы можете написать комментарии по этой книге, задать технические вопросы и получить помощь от автора и других пользователей. Этот форум расположен по адресу https://livebook.manning.com/#!/book/spark-in-actionsecond-edition/discussion. Вы можете также узнать больше о форумах Manning и правилах их использования по адресу https://livebook.manning.com/#!/discussion. К обязательствам издательства Manning по отношению к читателям относится предоставление места, где обеспечивается разумный диалог между отдельными читателями, а также между читателями и автором книги. Но при этом автор не обязан обеспечивать какой-либо конкретный объем своего участия в обсуждении, его участие в этом форуме является добровольным (и не оплачивается). Мы предлагаем читателям попытаться задать автору действительно трудные и интересные вопросы, чтобы его интерес к форуму не угас. Форум и архивы предыдущих обсуждений будут доступными на сайте издателя сразу после выхода книги из печати.
Отзывы и пожелания Мы всегда рады отзывам наших читателей. Расскажите нам, что вы думаете об этой книге, – что понравилось или, может быть, не понравилось. Отзывы важны для нас, чтобы выпускать книги, которые будут для вас максимально полезны. Вы можете написать отзыв на нашем сайте www.dmkpress.com, зайдя на страницу книги и оставив комментарий в разделе «Отзывы и рецензии». Также можно послать письмо главному редактору по адресу [email protected]; при этом укажите название книги в теме письма. Если вы являетесь экспертом в какой-либо области и заинтересованы в написании новой книги, заполните форму на нашем сайте по адресу
О чем эта книга
31
http://dmkpress.com/authors/publish_book/ или напишите в издательство по адресу [email protected].
Скачивание исходного кода примеров Скачать файлы с дополнительной информацией для книг издательства «ДМК Пресс» можно на сайте www.dmkpress.com или www.дмк.рф на странице с описанием соответствующей книги.
Список опечаток Хотя мы приняли все возможные меры для того, чтобы обеспечить высокое качество наших текстов, ошибки все равно случаются. Если вы найдете ошибку в одной из наших книг, мы будем очень благодарны, если вы сообщите о ней главному редактору по адресу [email protected]. Сделав это, вы избавите других читателей от недопонимания и поможете нам улучшить последующие издания этой книги.
Нарушение авторских прав Пиратство в интернете по-прежнему остается насущной проблемой. Издательства «ДМК Пресс» и Wiley очень серьезно относятся к вопросам защиты авторских прав и лицензирования. Если вы столкнетесь в интернете с незаконной публикацией какой-либо из наших книг, пожалуйста, пришлите нам ссылку на интернет-ресурс, чтобы мы могли применить санкции. Ссылку на подозрительные материалы можно прислать по адресу электронной почты [email protected]. Мы высоко ценим любую помощь по защите наших авторов, благодаря которой мы можем предоставлять вам качественные материалы.
Об авторе Жан-Жорж Перрен (Jean-Georges Perrin) страстно увлечен инженерией программного обеспечения и всем, что касается использования данных. В своих последних проектах он в еще большей степени устремлен к идее инженерии распределенной обработки данных. В этих проектах ЖанЖорж активно использует Apache Spark, Java и другие инструментальные средства в гибридных облачных средах. Он гордится тем, что первым во Франции был удостоен звания IBM Champion на двенадцатом году непрерывной работы в этой компании. Как признанный эксперт в области обработки данных и инженерии программного обеспечения, в настоящее время Жан-Жорж работает во многих странах мира, но чаще всего в США, где он проживает. Своим более чем 25-летним опытом в области информационных технологий Жан-Жорж делится как участник конференций и автор статей в печатных изданиях и в интернете. Вы можете посетить его блог по адресу http://jgp.net.
Иллюстрация на обложке Рисунок на обложке книги «Spark на практике» называется «Homme et Femme de Housberg, près Strasbourg» (Мужчина и женщина из Хусберга, близ Страсбурга). Впоследствии Хусберг стал Хаусбергеном, природным регионом и исторической территорией в Эльзасе, и теперь разделен между тремя поселками: Нидерхаусбергеном (Нижний Хаусберген), Миттельхаусбергеном (Средний Хаусберген) и Оберхаусбергеном (Верхний Хаусберген). Иллюстрация взята из коллекции рисунков традиционной одежды разных стран художника Жака Грассе де Сен-Совёр (Jacques Grasset de Saint-Sauveur), озаглавленной «Costumes de Différents Pays» и изданной во Франции в 1797 году. Каждая иллюстрация тщательно прорисована и раскрашена вручную. Иллюстрация на обложке имеет особый смысл для меня. Я действительно счастлив тем, что могу использовать этот рисунок для своей книги. Я родился в Страсбурге, в Эльзасе, который сейчас находится во Франции. Для меня чрезвычайно важно мое эльзасское происхождение. Когда я решил переехать в США, я понимал, что расстаюсь с частичкой этой культуры, со своей семьей, с моими родителями и сестрами. Мои родители живут в маленьком городке Суффельвейершейм, совсем рядом с Нидерхаусбергеном. Эта иллюстрация напоминает мне о родителях каждый раз, когда я смотрю на обложку (хотя у моего папы гораздо меньше волос на голове). Богатое разнообразие рисунков из коллекции Жака Грассе де СенСовёр живо напоминает нам, как отличаются в культурном плане города и регионы мира от существовавших всего лишь 200 лет назад. Изолированные друг от друга, люди говорили на разных диалектах (в моем случае на эльзасском) и даже на разных языках. На городских улицах или в сельской местности легко было определить, кто где живет и какие существуют привычки и уклад жизни, только по одежде обитателей. С тех пор изменилась одежда, и различия между регионами, ранее столь заметные, ушли в прошлое. Теперь трудно отличить друг от друга даже обитателей различных континентов, не говоря уж о различных городах, регионах и странах. Возможно, мы лишились культурных раз-
34
Иллюстрация на обложке
личий, предпочитая им более разнообразную и насыщенную личную жизнь, – особенно в современном многоликом и быстро меняющемся технологическом мире. В наше время, когда трудно отличить одну книгу о компьютерах от другой, издательство Manning отмечает изобретательность и инициативность компьютерного бизнеса с помощью обложек книг, изображающих коренные различия жизни в разных регионах два века назад, снова оживляя рисунки Жака Грассе де Сен-Совёр.
Часть I Теория, разбавленная превосходными примерами П
ри освоении любой технологии необходимо хотя бы немного знать и понимать «скучную» теорию, прежде чем приступать к практическому использованию. Я включил в эту часть шесть глав, которые предоставят подробный обзор теоретических концепций, объясняемых на примерах. В главе 1 представлено общее введение с простым примером. Вы узнаете, почему Spark представляет собой не просто обычный набор инструментов, а настоящую распределенную аналитическую операционную систему. После прочтения первой главы вы будете готовы к выполнению простой процедуры потребления данных в Spark. Глава 2 продемонстрирует, как работает Spark на высоком (внешнем) уровне. Вы постепенно выстроите представление о компонентах Spark, формируя мысленную модель (представляющую ваш собственный мыслительный процесс) шаг за шагом. Лабораторная работа в этой главе продемонстрирует, как экспортировать данные в базу данных. В этой главе очень много иллюстраций, которые должны способствовать процессу обучения, дополняя текст и исходный код. Глава 3 помещает вас в совершенно новое измерение: исследование мощного фрейма данных, который объединяет прикладной интерфейс API и возможности хранения данных Spark. В лабораторной работе этой главы вы загрузите два набора данных и объедините их. В главе 4 воздается хвала лени (ленивым, или отложенным, вычислениям) и объясняется, почему Spark использует ленивую, или отложенную, оптимизацию. Будет описан направленный ациклический граф (НАГ; DAG), потом приведено сравнение Spark и СУРБД. Лабораторная работа научит вас основам обработки данных с использованием API фрейма данных. Главы 5 и 6 взаимосвязаны: вы напишете небольшое приложение, создадите кластер и развернете в нем это приложение. В этих двух главах содержится только практическая информация.
1
Так что же такое Spark?
Краткое содержание главы: что такое Spark и где он используется; основы технологии распределенной обработки данных; четыре столпа Spark; хранилище данных и прикладные интерфейсы API: великолепный фрейм данных.
Когда я был ребенком в 1980-х годах, открывающим для себя мир программирования с помощью языка Basic и домашнего компьютера Atari, я не мог понять, почему невозможно автоматизировать основные законы, регулирующие деятельность, как, например, ограничение скорости, нарушения правил на светофоре и счетчик оплаты за стоянку автомобиля. Все выглядело достаточно простым – в книге, которую я читал, было сказано: чтобы стать хорошим программистом, нужно избегать использования операторов GOTO. Именно так я и поступил, пытаясь структурировать свой код, начиная с 12 лет. Но я никоим образом не мог вообразить реальный объем обрабатываемых данных (и появление и стремительное развитие интернета вещей – Internet of Things, IoT), когда разрабатывал игру в стиле Монополии. Поскольку моя игра умещалась в 64 Кб оперативной памяти, я даже и представить себе не мог, что наборы данных должны будут увеличиваться (с гигантским коэффициентом увеличения) или что данные могут обладать скоростью, и терпеливо ждал, когда моя игра сохранится на магнитной ленте в накопителе Atari 1010. Быстро пролетели 35 лет, и все способы автоматизации, о которых я мечтал, стали доступными (а моя игра стала пустяковым «детским лепетом»). Объемы данных росли быстрее, чем технологии аппаратного
Общая картина: что такое Spark и что он делает
37
обеспечения для поддержки их обработки1. Кластер из небольших (настольных) компьютеров мог стоить дешевле, чем один большой компьютер (мейнфрейм). Память подешевела в два раза по сравнению с 2005 годом, а память в 2005 году была в пять раз дешевле, чем в 2000-м2. Сети стали быстрее в несколько раз, а современные центры обработки данных (datacenters) предлагают скорость до 100 Гб/с (Gbps), это приблизительно в 2000 раз быстрее, чем ваш домашний Wi-Fi пять лет назад. Это были лишь некоторые из причин, заставивших людей задать следующий вопрос: как можно использовать вычисления с распределенной памятью для анализа больших объемов данных? Когда вы читаете техническую литературу или ищете в вебе информацию об Apache Spark, возможно, вам встретятся утверждения о том, что это инструмент для обработки больших данных, преемник Hadoop, платформа для выполнения анализа, фреймворк (рабочая среда) на основе кластера компьютеров, и тому подобные высказывания. Que nenni3! ЛАБОРАТОРНАЯ РАБОТА Лабораторная работа в этой главе доступна в репозитории GitHub по адресу https://github.com/jgperrin/ net.jgp.books.spark.ch01. Это лабораторная работа #400. Если вы не знакомы с сервисом GitHub и интегрированной средой разработки Eclipse, то в приложениях A, B, C, D вы найдете справочное руководство.
1.1
Общая картина: что такое Spark и что он делает Подобно тому, как Маленький Принц сказал Антуану де Сент-Экзюпери: «Нарисуй мне барашка», можно было бы сказать: «Нарисуй мне Spark». В этом разделе вы узнаете о том, что такое Spark, а затем – что может делать Spark, на нескольких конкретных примерах его использования. Завершается этот раздел описанием того, как Spark интегрируется в качестве стека программного обеспечения с другими программными комплексами и используется учеными-исследователями в области обработки данных.
1.1.1 Что такое Spark Spark – это не просто стек программного обеспечения для научных работников в области обработки данных. При создании приложений вы строите их «поверх» или на основе операционной системы, как показано на рис. 1.1. Операционная система предоставляет сервисы, упрощающие 1
2
3
См. статью «Intel Puts the Brakes on Moore’s Law» Тома Симоните (Tom Simonite) в MIT Technology Review, март 2016 года (http://mng.bz/gVj8). См. статью «Memory Prices (1957–2017)» Джона С. МакКаллума (John C. McCallum) (https://jcmit.net/memoryprice.htm). Средневековое французское выражение, означающее: «Разумеется, нет!»
38
Глава 1 Так что же такое Spark?
разработку приложения, другими словами, вам не нужно формировать файловую систему или писать сетевой драйвер для каждого разрабатываемого приложения. Вы пишете приложения, используя сервисы, предлагаемые операционной системой
Операционная система создает уровень абстракции над аппаратурой и предлагает сервисы для разработчиков приложений
Аппаратура чаще всего скрыта и невидима (для пользователей), особенно при современном подходе «все в облаке»
Рис. 1.1 Когда вы пишете приложения, то используете сервисы, предлагаемые операционной системой, которая изолирует вас от прямого взаимодействия с аппаратурой
Вместе с потребностью в большей вычислительной мощности возникает и постоянно возрастающая потребность в распределенных вычислениях (в распределенной обработке данных). После появления технологии распределенных вычислений в распределенные приложения должны были включаться соответствующие функции. На рис. 1.2 показано увеличение сложности при добавлении дополнительных компонент в распределенное приложение. Вы добавляете возможности распределенных вычислений и анализа данных в свое приложение с помощью библиотек
Операционная система создает уровень абстракции над аппаратурой одного узла Аппаратура остается невидимой, но в вашем приложении требуется обработка аварийных ситуаций, восстановление, обеспечение доступности узлов…
Рис. 1.2 Один из способов создания распределенных приложений, специализированных для обработки данных, – встраивание всех управляющих элементов на уровне приложения с использованием библиотек или других программных компонент. В результате размер приложений увеличивается и их сопровождение усложняется
После этого необходимо добавить, что Apache Spark может показаться сложной системой, для применения которой потребуется огромный
Общая картина: что такое Spark и что он делает
39
объем предварительных знаний. Я уверен, что вам необходимы только навыки работы с Java и системами управления реляционными базами данных (СУРБД) для понимания, использования и создания приложений, а также для расширения самой системы Spark. Приложения тоже стали более интеллектуальными – генерируют отчеты и выполняют анализ данных (в том числе агрегацию данных, линейную регрессию или просто выводят кольцевые диаграммы). Таким образом, если нужно добавить аналитические функциональные возможности подобного рода в приложение, то необходимо подключить (связать) соответствующие библиотеки или написать свои. Из-за этого приложение увеличивается в размерах (или становится «толще», как «толстый клиент»), затрудняется его сопровождение, и само приложение становится более сложным и, как следствие, более дорогим для предприятия. Вы можете спросить: «Так почему бы не переместить всю эту функциональность на уровень операционной системы?» Преимуществ перемещения этих функциональных свойств на более низкий уровень, например на уровень операционной системы, несколько, в том числе следующие: предоставление стандартного способа работы с данными (в определенной степени это похоже на язык структурированных запросов – Structured Query Language, SQL для реляционных баз данных); снижение стоимости разработки (и сопровождения) приложений; возможность сосредоточиться на том, как использовать конкретный инструмент, а не на том, как он работает (например, Spark выполняет распределенное потребление данных, и вы можете узнать, как извлечь преимущества из этого процесса без необходимости тщательного изучения того, как именно Spark выполняет эту задачу). Это как раз то, чем Spark стал для меня: аналитической операционной системой. На рис. 1.3 показан этот программный стек в упрощенной форме. Приложения используют полнофункциональный комплект прикладных интерфейсов API для обработки данных, анализа, машинного обучения, поддержки искусственного интеллекта…
Операционная система создает уровень абстракции над аппаратурой одного узла Аппаратура полностью изолирована (абстрагирована) операционной системой и Spark
Рис. 1.3 Apache Spark упрощает разработку приложений, специально предназначенных для анализа данных, предлагая сервисы для этих приложений точно так же, как операционная система
40
Глава 1 Так что же такое Spark?
В этой главе мы рассмотрим несколько конкретных примеров использования Apache Spark в различных отраслях промышленности и в проектах разных масштабов. Эти примеры помогут получить начальное представление о том, чего можно достичь. Я твердо уверен в том, что для лучшего понимания современности мы должны обращаться к истории. Это в полной мере применимо и к сфере информационных технологий (ИТ): см. приложение E, если вы принимаете мою точку зрения. Теперь, когда декорации размещены на сцене, можно начать углубленное изучение Spark. Начнем с общего обзора, рассмотрим хранилища данных и прикладные интерфейсы API, а в конце главы разберем первый пример.
1.1.2 Четыре столпа маны По представлениям полинезийцев, мана (mana) – это энергия основных сил природы, заключенная в объекте или в человеке. Это определение соответствует общей схеме, которую можно найти в комплекте документации Spark. Схема изображает четыре столпа, приносящие природные силы в Spark: Spark SQL, потоковый механизм Spark Streaming, Spark MLlib (для машинного обучения) и GraphX, стоящие на прочном фундаменте Spark Core. Это точное представление программного стека Spark, но я считаю его не совсем полным. Представление стека должно быть расширено, чтобы показать аппаратуру, операционную систему и само приложение, как на рис. 1.4. Разумеется, кластер(ы), в котором работает Spark, возможно, не используется исключительно вашим приложением, но в своей работе вы будете использовать следующие компоненты: Spark SQL – для выполнения операций с данными, таких как обычные задания на языке SQL в СУРБД. Spark SQL предлагает прикладные интерфейсы API и SQL для обработки данных. Spark SQL будет рассматриваться в главе 11, а дополняться эта тема будет в большинстве последующих глав. Spark SQL – это краеугольный камень Spark; Spark Streaming – потоковый механизм Spark и особенно структурированный потоковый механизм Spark – предназначен для анализа потоковых данных. Стандартизированный API Spark поможет обрабатывать данные в одинаковом стиле независимо от того, являются ли данные потоковыми или пакетными. Подробнее о потоковой обработке данных вы узнаете в главе 10; Spark MLlib – для машинного обучения и дальнейших расширений для глубокого обучения. Машинное обучение, глубокое обучение и искусственный интеллект заслуживают отдельной книги; GraphX – для интенсивного использования графовых структур данных. Чтобы узнать больше о GraphX, вы можете прочесть книгу «Spark GraphX in Action» Майкла Малака (Michael Malak) и Робина Иста (Robin East) (Manning, 2016).
Как можно использовать Spark
41
Рис. 1.4 Ваше приложение, как и другие приложения, имеет дело с четырьмя столпами Spark – SQL, потоковым механизмом, машинным обучением и графами – через стандартизированный прикладной интерфейс API. Spark защищает вас от ограничений, присущих операционной системе и аппаратуре: нет необходимости заботиться о том, где запускается приложение или предоставлены ли ему правильные данные. Spark позаботится об этом. Но приложение может получить доступ к операционной системе или к аппаратуре, если это действительно необходимо
1.2
Как можно использовать Spark В этом разделе подробно рассматривается, как можно использовать Spark, и основное внимание сосредоточено на обычных вариантах обработки данных, а также на подходе с использованием науки о данных. Неважно, являетесь ли вы инженером по обработке данных или ученымисследователем в области обработки данных, в любом случае вы сможете воспользоваться Apache Spark в своей работе.
1.2.1 Spark в процессе обработки данных / инженерии данных Spark может обрабатывать данные несколькими различными способами. Но он превосходен при обработке больших данных, когда данные
42
Глава 1 Так что же такое Spark?
потребляются, очищаются, преобразовываются и публикуются результаты обработки. Я предпочитаю определять инженеров по обработке данных как специалистов по подготовке данных и по обеспечению и организации процесса обработки данных. Они обеспечивают доступность и готовность данных, надлежащее применение правил по соблюдению качества обработки данных, успешное выполнение преобразований и доступность данных для других систем и подразделений, включая бизнес-аналитиков и ученых-исследователей в области обработки данных. Инженеры по обработке данных также могут быть теми специалистами, которые принимают результаты работы ученых-исследователей и внедряют их в производственную практику. Spark – превосходный инструмент для инженеров по обработке данных. Ниже перечислены четыре этапа обычного варианта использования Spark (с большими данными) в процессе инжиниринга данных. 1 Потребление данных. 2 Улучшение качества данных (data quality – DQ). 3 Преобразование данных. 4 Публикация результатов обработки. На рис. 1.5 показан этот процесс.
Рис. 1.5 Spark в обычном варианте обработки данных. Первый этап – потребление данных. На этом этапе исходные данные «сырые» (необработанные), возможно, далее потребуется применение некоторых методов улучшения качества данных (DQ). После этого данные готовы к преобразованию. После преобразования данные становятся «обогащенными». Наступает время их публикации или совместного использования, чтобы сотрудники вашей организации могли выполнять какие-либо действия с этими данными и принимать решения на их основе
Показанный на рис. 1.5 процесс включает четыре этапа, и после каждого этапа данные перемещаются в соответствующую зону (zone): 1 потребление данных – Spark может потреблять данные из разнообразных источников (о потреблении данных см. главы 7, 8 и 9).
Как можно использовать Spark
2
3
4
1
2
43
Если невозможно найти поддерживаемый формат, то можно создать собственные источники данных. На этом этапе я называю данные исходными («сырыми», необработанными – raw data). Встречаются также следующие названия этой зоны: сосредоточение (staging), посадочная площадка (landing), бронзовая (bronze) зона или даже болото (swamp); улучшение качества данных – перед обработкой данных, вероятно, потребуется проверка их качества. Пример обеспечения качества данных (DQ) – проверка с целью убедиться в том, что все даты рождения указаны в прошлом. Частью этого процесса также может стать выборочное скрытие некоторых данных: при обработке номеров социальной страховки (SSN) в сфере здравоохранения можно обеспечить недоступность SSN для разработчиков и для неавторизованных сотрудников1. Этап после улучшения качества данных я называю зоной очищенных данных (pure data). Встречаются также следующие названия этой зоны: рафинировочная (refinery), серебряная (silver), бассейн (pond), песочница (sandbox) или зона обследования (exploration zone); преобразование данных – следующий этап – обработка данных. Можно объединять данные с другими наборами данных, применять специализированные функции, выполнять операции агрегирования, реализовывать методы машинного обучения и много другое. Цель этого этапа – получение «обогащенных» (обработанных) данных (rich data) как результата аналитической работы. В большинстве глав этой книги обсуждается преобразование данных. Эта зона может также называться продукционной (production), золотой (gold), зоной улучшенных данных (refined), лагуной (lagoon) или эксплуатационной зоной (operationalization zone); загрузка и публикация – как и в процессе ETL2, на завершающем этапе можно загрузить данные в хранилище данных (data warehouse), используя инструментальное средство бизнес-интеллекта (business intelligence – BI), вызывая прикладные интерфейсы API или сохраняя данные в файле. Результатом являются данные, готовые к использованию в конкретной организации (на предприятии).
Если вы проживаете не в США, то должны понять, насколько важен номер социальной страховки SSN. Фактически SSN управляет всей жизнью владельца. С его первоначальной целью – идентификатор для получения социальных льгот – связи почти не осталось: в настоящее время SSN стал идентификатором для уплаты налогов и для обеспечения анонимности финансовых операций, а также для отслеживания деятельности людей. Злоумышленники специально ищут номера SSN и другие личные данные людей, чтобы открывать от их имени банковские счета или получить доступ к существующим финансовым счетам. ETL – Extract, Transform, Load – извлечение, преобразование, загрузка – основной (классический) процесс в крупном хранилище данных (data warehouse).
44
Глава 1 Так что же такое Spark?
1.2.2 Spark в научных исследованиях в области обработки данных Ученые-исследователи в области обработки данных применяют методики, немного отличающиеся от подхода инженеров программного обеспечения или инженеров по обработке данных, поскольку главное внимание ученых сосредоточено на этапе преобразования данных, осуществляемом в интерактивном режиме. Для этой цели исследователи в области обработки данных используют разнообразные инструментальные средства, например такие как виртуальные блокнотные среды (notebook) Jupyter, Zeppelin, IBM Watson Studio и Databricks Runtime. Результаты исследований в области обработки данных, несомненно, будут иметь значение для вас, но в исследовательских проектах обработки данных будут использоваться корпоративные данные, так что на завершающем этапе данные могут передаваться ученым, а результаты их исследований (такие как модели машинного обучения) применяются в корпоративных хранилищах данных или в процессе внедрения в производство исследовательских методов. Таким образом, диаграмма последовательностей в стиле UML, показанная на рис. 1.6, немного точнее объясняет, как ученые-исследователи в области обработки данных используют Spark. Если вы хотите больше знать о Spark и науке о данных, то можете ознакомиться со следующими книгами: «PySpark in Action», автор Джонатан Риу (Jonathan Rioux) (Manning, 2020, www.manning.com/books/pyspark-in-action?a_aid=jgp); «Mastering Large Datasets with Python», автор Джон Т. Уолохан (John T. Wolohan) (Manning, 2020, www.manning.com/books/masteringlarge-datasets-with-python?a_aid=jgp). В примере использования, показанном на рис. 1.6, данные загружаются в Spark, затем пользователь работает с ними, применяя методы преобразования, и выводит (предъявляет) часть этих данных. Вывод данных не означает завершение процесса. Пользователю предоставляется возможность продолжать процесс в интерактивном режиме, как в обычном бумажном блокноте, где записываются рецепты, заметки и т. п. На завершающем этапе процесса пользователь виртуальной блокнотной среды может сохранить данные в файлах или в базах данных или сформировать (интерактивные) отчеты.
45
Что можно делать с помощью Spark
Ввод некоторого кода (Python, Scala, R): загрузка данных из источника
Запрос к Spark: загрузка источника данных Доступ к данным в источнике Данные ОК
ОК
Выполнение преобразования или действия, например предъявление данных
ОК, и в случае запроса на предъявление данных возврат требуемых данных
Запрос к Spark: выполнение преобразования
ОК, и в случае запроса на предъявление данных возврат требуемых данных
Внутри цикла пользователь также может загружать другие наборы данных
Рис. 1.6 Диаграмма последовательностей для ученого-исследователя в области обработки данных, использующего Spark: пользователь «разговаривает» с виртуальной блокнотной средой (notebook), которая вызывает Spark при необходимости. Spark напрямую выполняет операции потребления данных. Каждый квадрат обозначает конкретный этап, каждая стрелка представляет последовательность действий. Такую диаграмму следует читать в хронологическом порядке, начиная с ее вершины
1.3
Что можно делать с помощью Spark Spark используется в проектах разнообразных типов, поэтому мы рассмотрим лишь некоторые такие проекты. Во всех вариантах использования подразумеваются данные, которые невозможно хранить и обрабатывать на одном компьютере (т. е. большие данные), таким образом, требуется кластер компьютеров, следовательно, необходима распределенная операционная система, специализированная для анализа данных.
Глава 1 Так что же такое Spark?
46
Определение больших данных (big data) со временем изменялось – от данных с характеристиками, известных как «пять V»1, до определения «данных, которые невозможно разместить на одном компьютере». Мне не нравится это определение – вероятно, вам известно, что многие СУРБД разделяют хранимые данные между несколькими серверами. Как и для многих теоретических концепций, скорее всего, потребуется собственное определение. Надеюсь, что книга поможет вам в этом. Для меня большие данные — это комплект наборов данных, доступных в любом пункте корпоративной среды, собранных (агрегированных) в одной локации, в которой можно выполнять основные аналитические операции для реализации более сложных аналитических функций, таких как машинное обучение и глубокое обучение. Такие укрупненные наборы данных могут стать основой для методик искусственного интеллекта (ИИ; artificial intelligence – AI). Для этой концепции абсолютно не важны конкретные технологии, размер и количество компьютеров. Spark, благодаря своим аналитическим функциональным возможностям и собственной распределенной архитектуре, может обрабатывать большие данные независимо от того, считаете ли вы данные действительно большими, и от возможности их размещения на одном или на нескольких (или даже многих) компьютерах. Просто нужно помнить о том, что вывод обычного отчета на широком 132-знаковом матричном принтере – это не самый типичный вариант использования Spark. Рассмотрим несколько примеров из реальной практической деятельности.
1.3.1 Spark прогнозирует качество пунктов питания Северной Каролины Почти везде в США для ресторанов (и прочих пунктов питания) обязательны инспекторские проверки местными отделами здравоохранения для проверки работы этих заведений и оценки на основе таких проверок. Более высокая оценка означает не лучшее качество пищи, а позволяет узнать, не подвергаете ли вы опасности свою жизнь, съев барбекю в какой-то забегаловке во время поездки в южные штаты. Оценивается чистота кухни, правильность хранения продуктов и многие другие критерии, для того чтобы (как все мы надеемся) избежать пищевых отравлений и прочих недомоганий. В Северной Каролине рестораны оцениваются по шкале от 0 до 100. Каждый округ предоставляет доступ к ресторанным оценкам, но централизованный пункт доступа к информации по всему штату отсутствует. 1
Пять V (five Vs) – это volume – объем (количество генерируемых и сохраняемых данных), variety – разнообразие (тип и природа данных), velocity – скорость (с которой данные генерируются и обрабатываются), variability – непостоянство (несогласованность или отсутствие целостности в наборе данных) и veracity – достоверность (качество данных может изменяться в весьма широких пределах); определение сформировано на основе информации из «Википедии» и от компании IBM.
Что можно делать с помощью Spark
47
NCEatery.com – это ориентированный на клиентов веб-сайт, на котором расположен список ресторанов с инспекторскими оценками за некоторый интервал времени. Цель этого сайта – централизованный доступ к информации и выполнение прогностического анализа по ресторанам, чтобы клиенты могли найти образцы качественных ресторанов. «Неужели то место, которое так понравилось мне два года назад, скатывается все ниже и ниже?» Во внутренней компоненте этого сайта Apache Spark потребляет наборы данных о ресторанах, инспекторских проверках и данные о нарушениях норм и правил, приходящие из различных округов, перемалывает эти данные и публикует сводные отчеты о результатах обработки на сайте. На этапе обработки применяются некоторые методики улучшения качества данных, а также методы машинного обучения, чтобы попытаться спрогнозировать результаты инспекторских проверок и оценки. Spark обрабатывает 1,6×1021 элементов (точек) данных и публикует около 2500 страниц каждые 18 ч, используя для этого небольшой кластер. Этот постоянно развивающийся проект включает в процесс обработки все большее количество округов Северной Каролины.
1.3.2 Spark обеспечивает быструю передачу данных для Lumeris Lumeris – это компания информационного обеспечения служб здравоохранения, расположенная в Сент-Луисе, штат Миссури. Компания постоянно помогает органам здравоохранения получить больше полезной информации из имеющихся данных. Для высокотехнологичной ИТсистемы компании потребовалось существенное ускорение, чтобы обслуживать больше клиентов и обеспечить более мощные средства внутренней обработки имеющихся данных. В компании Lumeris Apache Spark, как часть процессов инженерии данных, потребляет тысячи файлов в формате CSV (comma-separated values – значения, разделяемые запятыми), хранящихся на сайте Amazon Simple Storage Service (S3), создает ресурсы по стандарту здравоохранения HL7 FHIR1 и сохраняет их в специализированном хранилище документов, где они могут использоваться как существующими приложениями, так и новым поколением клиентских приложений. Такой стек технологий позволяет компании Lumeris продолжать свой рост и развитие в плане объемов обрабатываемых данных и приложений. В дальнейшем с помощью этой технологии компания Lumeris надеется обеспечить сохранность многих жизней. 1
Health Level Seven International (HL7) – это некоммерческие, утвержденные ANSI стандарты для организаций, занимающихся обменом, сбором и объединением, совместным использованием и извлечением информации в области здравоохранения, представленной в электронном виде. Стандарт HL7 поддерживают более 1600 участников из более чем 50 стран. Fast Healthcare Interoperability Resources (FHIR) – одна из самых последних спецификаций стандартов по обмену информацией в области здравоохранения.
Глава 1 Так что же такое Spark?
48
1.3.3 Spark анализирует журналы наблюдения за оборудованием CERN CERN, или Европейская организация ядерных исследований, была основана в 1954 году. Здесь находится Большой адронный коллайдер (LHC – Large Hadron Collider), 27-километровое кольцо, расположенное на глубине 100 м под землей на границе Франции и Швейцарии, в Женеве. Здесь проводятся крупномасштабные физические эксперименты, генерирующие 1 Петабайт (Пб) данных в секунду. После значительной фильтрации объем данных сокращается до 900 Гб в день. После экспериментов с Oracle, Impala и Spark группа CERN на основе Spark создала сервис Next CERN Accelerator Logging Service (NXCALS) в собственном локальном облаке под управлением OpenStack, в котором насчитывается до 250 000 ядер. Пользователями этой впечатляющей архитектуры являются ученые (использующие специализированные приложения и виртуальные блокнотные среды Jupyter), разработчики и различные приложения. Дальнейшая цель CERN – предоставление постоянного доступа к еще большему объему данных и увеличение общей скорости обработки данных.
1.3.4 Другие варианты использования Spark применялся во многих других вариантах использования, включая следующие: создание интерактивных инструментальных средств так называемого выпаса данных (data-wrangling), таких как виртуальные блокнотные среды IBM Watson Studio и Databricks; наблюдение за качеством видео, передаваемого по телевизионным каналам, таким как MTV или Nickelodeon1; наблюдение за участниками онлайновой видеоигры с целью выявления некорректного поведения и регулирования взаимодействия игроков в псевдореальном времени для достижения всеми игроками максимально возможного положительного опыта; компания Riot Games.
1.4
Почему вам очень понравится фрейм данных Моя цель в этом разделе – сделать так, чтобы вам очень понравился фрейм данных. Вы узнаете только то, что стимулирует вас к дальнейшему изучению, и вы узнаете больше в главе 3 и последующих главах книги. Фрейм данных (dataframe) – это совокупность контейнера данных и прикладного интерфейса API. Концепция фрейма данных чрезвычайно важна в Spark. Тем не менее эту концепцию понять не так уж сложно. Вы будете постоянно исполь1
См. статью «How MTV and Nickelodeon Use Real-Time Big Data Analytics to Improve Customer Experience», автор Бернард Марр (Bernard Marr), Forbes, January 2017 (http://bit.ly/2ynJvUt).
Почему вам очень понравится фрейм данных
49
зовать фреймы данных. В этом разделе объясняется, что такое фрейм данных с точки зрения Java (инженера по программному обеспечению) и с точки зрения СУРБД (инженера по обработке данных). После ознакомления с этими точками зрения с приведением некоторых аналогий в конце раздела будет представлена диаграмма.
Примечание. Вопрос правописания В литературе вам в большинстве случаев будет встречаться другой вариант написания термина: DataFrame. Я решил придерживаться варианта, общепринятого в англоязычной литературе, который, соглашусь, может казаться непривычным для людей, говорящих по-французски. Как бы то ни было, несмотря на свое «королевское величие», фрейм данных – dataframe – остается обычным существительным, поэтому нет причин использовать то тут, то там буквы верхнего регистра. Здесь вам не какая-нибудь забегаловка!
1.4.1 Фрейм данных с точки зрения Java Если вы хорошо знакомы с языком программирования Java и имеете некоторый опыт использования Java Database Connectivity (JDBC), то фрейм данных для вас будет выглядеть приблизительно так: ResultSet. Он содержит данные, у него есть API… Фрейм данных и ResultSet обладают следующими одинаковыми свойствами: доступ к данным осуществляется через простой API; можно получить доступ к схеме. Но есть и некоторые отличия фрейма данных от ResultSet: нет возможности последовательного просмотра с помощью метода next(); API расширяется с помощью функций, определенных пользователем (UDF). Можно написать свой код или обертку для существующего кода и добавить в Spark. Далее этот код будет доступным в распределенном режиме. Функции, определенные пользователем (UDF), рассматриваются в главе 16; если необходим доступ к данным, то сначала нужно получить строку Row, затем перемещаться по столбцам этой строки с помощью методов типа get (это похоже на ResultSet); метаданные достаточно просты, так как они не являются главными или внешними ключами или индексами в Spark. В Java фрейм данных реализован как Dataset (произносится как «a dataset of rows» – набор данных, состоящий из строк).
1.4.2 Фрейм данных с точки зрения СУРБД Если вы имеете опыт работы с СУРБД, то, возможно, считаете, что фрейм данных – это нечто похожее на таблицу. Фрейм данных и таблица действительно имеют следующие одинаковые свойства:
Powered by TCPDF (www.tcpdf.org)
Глава 1 Так что же такое Spark?
50
данные размещены в столбцах и строках; столбцы строго типизированы. Фрейм данных отличается от таблицы СУРБД следующими свойствами: данные могут быть вложенными, как в документе в формате JSON или XML. В главе 7 описано потребление таких документов, и вы будете использовать вложенные конструкции такого типа в главе 13; невозможно обновлять или удалять целые строки; вы создаете новый фрейм данных; можно с легкостью добавлять или удалять столбцы; в фрейме данных нет ограничений, индексов, главных и внешних ключей, триггеров.
1.4.3 Графическое представление фрейма данных Фрейм данных – это мощный инструмент, которым вы будете пользоваться на протяжении всей книги и во время работы со Spark. Его весьма эффективный API и возможности хранения данных выделяют фрейм данных как главный элемент среди всего, что его окружает. На рис. 1.7 показан один из вариантов графического представления API, реализации и хранилища фрейма данных.
Рис. 1.7 Графическое представление фрейма данных, его реализации на языке Java (Dataset), схемы и распределенного хранилища данных. Как разработчик вы будете использовать API набора данных, который позволит работать со столбцами и строками. К хранилищу, распределенному по разделам (узлам кластера), также можно получить доступ, в основном для оптимизации. О распределении по узлам кластера вы подробнее узнаете в главе 2
Первый пример
1.5
51
Первый пример Пора рассмотреть первый пример. Ваша задача – запустить Spark с простым приложением, которое считывает содержимое файла, сохраняет его в фрейме данных и выводит результат. Вы узнаете, как настраивать рабочую среду, которая будет использоваться на протяжении всей книги. Вы также научитесь взаимодействовать с рабочей средой Spark и выполнять основные операции. В дальнейшем вы увидите, что в большинстве глав содержатся лабораторные работы по темам соответствующей главы, в которых можно экспериментировать с исходным кодом. Для каждой лабораторной работы предлагается набор данных (по возможности взятый из реальной практической деятельности), а также один или несколько листингов с исходным кодом. Чтобы начать изучение примера, необходимо выполнить следующие действия: установить требуемое программное обеспечение, возможно, оно уже установлено в вашей системе: Git, Maven, Eclipse; загрузить исходный код методом клонирования из репозитория GitHub; выполнить пример, который загрузит простой файл в формате CSV (значения, разделенные запятыми) и выведет несколько строк.
1.5.1 Рекомендуемое программное обеспечение В этом разделе представлен список программ, которые вы будете использовать на протяжении всей книги. Подробные инструкции по установке требуемого программного обеспечения содержатся в приложениях А и B. В этой книге используется следующее программное обеспечение: Apache Spark 3.0.0; в основном ОС macOS Catalina, но примеры работают и в Ubuntu версий с 14 по 18, и в Windows 10; Java 8 (хотя не используется множество конструкций, введенных в версии 8, таких как лямбда-функции). Мне известно, что уже доступна версия Java 11, но большинство организаций слишком медленно переходят на более новую версию (кроме того, мне кажется немного запутанной новейшая стратегия развития Java компанией Oracle). На данный момент только Spark v3 сертифицирован для работы с Java 11. В примерах будет использоваться либо командная строка, либо интегрированная среда разработки Eclipse. Для работы в командной строке можно использовать следующее программное обеспечение: Maven – в книге используется версия 3.5.2, но любая более поздняя версия также будет работать; Git версии 2.13.6, но любая более поздняя версия также будет работать. В macOS можно воспользоваться версией, представленной
Глава 1 Так что же такое Spark?
52
в пакете Xcode. В Windows можно скачать пакет Git с сайта https:// git-scm.com/download/win. Если вы предпочитаете графические пользовательские интерфейсы (GUI) для работы с Git, то рекомендую программу Atlassian Sourcetree, которую можно загрузить с сайта www.sourcetreeapp.com.
1.5.2 Скачивание исходного кода Исходный код размещен в открытом репозитории на сайте GitHub. URL репозитория https://github.com/jgperrin/net.jgp.books.spark.ch01. В приложении D подробно описано, как использовать Git в командной строке и в Eclipse для загрузки исходного кода.
1.5.3 Запуск первого приложения Теперь вы готовы к запуску самого первого приложения. Если при запуске возникли какие-то проблемы, то вам должно помочь приложение R.
Командная строКа В командной строке необходимо перейти в рабочий каталог: $ cd net.jgp.books.spark.ch01
Затем выполните следующую команду: $ mvn clean install exec:exec
EclipsE После импорта проекта (см. приложение D) поместите файл приложения CsvToDataframeApp.java в Project Explorer. Щелкните правой кнопкой мыши по имени этого файла, затем выберите из контекстного меню пункт Run As > 2 Java Application, как показано на рис. 1.8. Посмотрите на полученный результат в консоли. Независимо от того, использовали вы командную строку или Eclipse, после нескольких секунд внутренней обработки вы должны увидеть результат, похожий на приведенный ниже: +---+--------+--------------------+-----------+--------------------+ | id|authorId| title|releaseDate| link| +---+--------+--------------------+-----------+--------------------+ | 1| 1|Fantastic Beasts ...| 11/18/16|http://amzn.to/2k...| | 2| 1|Harry Potter and ...| 10/6/15|http://amzn.to/2l...| | 3| 1|The Tales of Beed...| 12/4/08|http://amzn.to/2k...| | 4| 1|Harry Potter and ...| 10/4/16|http://amzn.to/2k...| | 5| 2|Informix 12.10 on...| 4/23/17|http://amzn.to/2i...| +---+--------+--------------------+-----------+--------------------+ здесь показано только 5 верхних строк
Теперь попробуем разобраться, что здесь произошло.
53
Первый пример
Щелкнуть правой кнопкой мыши для доступа к контекстному меню
Рис. 1.8
Щелкнуть для выбора пункта Run As
Щелкнуть для запуска приложения
Интегрированная среда разработки Eclipse с деревом проекта в Project Explorer
1.5.4 Первый исходный код для вас Наконец-то вы добрались до кода! В предыдущем разделе вы видели вывод результата. Пора запустить первое приложение, которое создает сеанс, обращается к Spark с запросом на загрузку файла в формате CSV, а затем выводит пять строк (не более) полученного набора данных. В листинге 1.1 приведен полный код программы. Когда дело доходит до представления исходного кода, следует вспомнить о существовании двух направлений мышления: одно направление придерживается абстрактного подхода в представлении кода, второе направление предпочитает представлять весь исходный код полностью, как есть. Я сторонник второго направления: мне нравится полный, за-
Глава 1 Так что же такое Spark?
54
вершенный код примеров больше, чем частичный. Мне не хотелось бы, чтобы вам пришлось самостоятельно домысливать отсутствующую часть кода или требуемые программные пакеты, даже если все это вполне очевидно. Листинг 1.1 Потребление данных в формате CSV package net.jgp.books.spark.ch01.lab100_csv_to_dataframe; import org.apache.spark.sql.Dataset; import org.apache.spark.sql.Row; import org.apache.spark.sql.SparkSession; public class CsvToDataframeApp { public static void main(String[] args) { CsvToDataframeApp app = new CsvToDataframeApp(); app.start(); }
❶
private void start() { SparkSession spark = SparkSession.builder() .appName("CSV to Dataset") .master("local") .getOrCreate();
❷
Dataset df = spark.read().format("csv") .option("header", "true") .load("data/books.csv");
❸
df.show(5);
❹
} }
❶ Функция main() – точка входа в приложение. ❷ Создание сеанса на локальном ведущем узле. ❸ Считывание файла books.csv в формате CSV и сохранение его содержимого в фрейме данных. ❹ Вывод не более пяти строк из созданного фрейма данных.
Хотя это простой пример, вы все же выполнили следующие действия: установили все компоненты, необходимые для работы со Spark (да, это так просто); создали сеанс, в котором может выполняться программный код; загрузили файл с данными в формате CSV; вывели пять строк из полученного набора данных. Теперь вы готовы к более глубокому изучению Apache Spark и пониманию того, что происходит внутри этой операционной системы.
Резюме
Spark – это аналитическая операционная система, которую можно использовать для обработки рабочей нагрузки и реализации алгоритмов в распределенном режиме. Spark пригоден не только для анализа:
Резюме
55
можно использовать его для передачи данных, для крупномасштабных преобразований данных, для анализа журналов и для решения многих других задач. Spark поддерживает SQL, Java, Scala, R и Python как интерфейсы программирования, но в этой книге рассматривается только Java (иногда Python). Основным внутренним хранилищем данных Spark является фрейм данных. Фрейм данных объединяет возможность хранения данных с прикладным интерфейсом API. Если у вас есть опыт разработки ПО с использованием JDBC, то вы обнаружите некоторые свойства, похожие на структуру JDBC ResultSet. Если у вас есть опыт разработки ПО для реляционных баз данных, то вы можете сравнить фрейм данных с таблицей с менее сложными метаданными. В Java фрейм данных реализован как Dataset. Можно быстро настроить Spark с помощью Maven и Eclipse. Spark не требует специализированной процедуры установки. Spark не ограничен применением алгоритма MapReduce: его API позволяет применять множество разнообразных алгоритмов для обработки данных. Потоковая обработка (streaming) все чаще и чаще используется в корпоративных приложениях, так как в деловой сфере требуется доступ к методам анализа в реальном времени. Spark поддерживает потоковую обработку данных. Анализ данных уже вышел за рамки простых объединений и агрегаций. В производственной сфере необходимо, чтобы «компьютеры думали за нас». Поэтому Spark поддерживает методы машинного обучения и глубокого обучения. Графы – специализированная методика применения анализа, но Spark поддерживает и графы.
2
Архитектура и рабочий процесс
Краткое содержание главы: создание мысленной (когнитивной) модели Spark для типового варианта использования; понимание соответствующего кода Java; изучение общей архитектуры приложения Spark; понимание рабочего процесса.
В этой главе вы создадите мысленную (когнитивную) модель Apache Spark. Мысленная (когнитивная) модель (mental model) – это объяснение того, как некая сущность работает в реальном мире с использованием собственного процесса мышления и приведенных ниже схем. Цель этой главы – помочь вам определить собственное представление о процессе мышления, по которому я вас проведу. Здесь используется много графических схем и немного кода. Такой подход должен сформировать весьма наглядное представление о создании особенной мысленной модели Spark. Эта модель описывает обычный (типовой) вариант, включающий загрузку, обработку и сохранение данных. Также будет рассматриваться код Java для выполнения этих операций. Рассматриваемый здесь вариант включает распределенную загрузку файла в формате CSV, выполнение простой операции и сохранение результата в базе данных PostgreSQL (и Apache Derby). Для понимания этого примера не требуются ни какие-либо знания о PostgreSQL, ни ее установка. Если вы знакомы с использованием других СУРБД и Java, то без труда освоите этот пример. В приложении F представлена дополнительная справочная информация о реляционных базах данных (советы, процедура установки, связи и т. д.).
Создание собственной мысленной (когнитивной) модели
57
ЛАБОРАТОРНАЯ РАБОТА Код и выборка данных доступны в репозитории на сайте GitHub: https://github.com/jgperrin/net.jgp. books.spark.ch02.
2.1
Создание собственной мысленной (когнитивной) модели В этом разделе вы создадите мысленную (когнитивную) модель Spark. В терминах программного обеспечения мысленная (когнитивная) модель – это концептуальное отображение (схема) того, что можно использовать для планирования, прогнозирования, диагностики и отладки приложений. Чтобы начать создание мысленной (когнитивной) модели, вы будете работать с вариантом обработки больших данных. При изучении этого варианта вы исследуете общую архитектуру Spark, рабочие процессы и терминологию. Это позволит лучше понять Spark в целом. Представьте себе следующий вариант обработки больших данных: вы – продавец книг, у которого имеется список авторов в файле. Необходимо выполнить простую операцию с содержимым этого файла, затем сохранить результат в базе данных. С технической точки зрения этот процесс выглядит следующим образом: 1 потребление (ingest) файла в формате CSV, как вы уже видели в главе 1; 2 преобразование (transform) данных: объединение фамилии и имени автора; 3 сохранение (save) полученного результата в реляционной базе данных. На рис. 2.1 показано, что должны сделать вы и Spark. Приложение, оно же драйвер (driver), устанавливает соединение с кластером Spark. После этого оно сообщает кластеру, что необходимо делать: приложение управляет кластером. В рассматриваемом здесь варианте ведущий узел (master) начинает с загрузки файла в формате CSV, а заканчивает сохранением полученного результата в базе данных. ПРИМЕР РАБОЧЕЙ СРЕДЫ Для лабораторной работы #100 я изначально использовал Spark v2.4.0, PostgreSQL v10.1 с JDBCдрайвером PostgreSQL v42.1.4 в ОС macOS v10.13.2 и Java 8. В лабораторной работе #110 используется Apache Derby v10.14.2.0 как внутренняя компонента (внутреннее звено). Код в основном тот же самый, поэтому если вы не хотите (или не можете) устанавливать PostgreSQL, то выполняйте лабораторную работу #110.
Глава 2 Архитектура и рабочий процесс
58
t0
Приложение (драйвер)
Приложение, также называемое драйвером, так как оно управляет ведущим
t1
Ведущий
t7
Приложение
Файл в формате CSV
База данных
График времени
Рис. 2.1 Везде в этой книге я использую специальные обозначения. Если они непонятны, прочтите раздел «О чем эта книга» в предисловии. Приложение (также называемое драйвером (driver)) устанавливает соединение с Apache Spark (ведущим – master), запрашивает загрузку файла в формате CSV, выполняет преобразование и сохраняет результат в базе данных. В левой части схемы можно видеть график времени (здесь расположены метки времени t0, t1 и t7). Как вы, вероятно, догадались, эти метки времени представляют этапы. Приложение является первым и последним элементом этого рабочего потока
2.2
Использование кода Java для создания мысленной (когнитивной) модели Прежде чем перейти к более глубокому изучению каждого этапа создания мысленной (когнитивной) модели, проанализируем приложение в целом. В этом разделе мы рассмотрим «внешнее оформление» кода Java, перед тем как разложить код на отдельные элементы и подробно описать каждую строку и ее предназначение. На рис. 2.2 показано простое представление процесса: Spark считывает файл в формате CSV, объединяет фамилию, запятую и имя, затем сохраняет весь преобразованный набор данных в базе данных.
Имя: Jean-Georges Фамилия: Perrin
Полное имя: Perrin, Jean-Georges
Имя: Jean-Georges Фамилия: Perrin Полное имя: Perrin, Jean-Georges
Рис. 2.2 Простой процесс, состоящий из трех этапов: считывание файла в формате CSV, выполнение простой операции объединения и сохранение полученных данных в базе данных
Использование кода Java для создания мысленной (когнитивной) модели
59
После запуска этого приложения вы получите простое сообщение: «Process complete» (Процесс завершен). На рис. 2.3 показан результат выполнения этого процесса. Получена таблица ch02 с тремя столбцами: fname, lname и новым столбцом, который вам нужен, name. Если необходима помощь при работе с базой данных, то обратитесь к приложению F.
Рис. 2.3 Данные из CSV-файла вместе с добавленным столбцом в базе данных PostgreSQL. Здесь показано использование SQLPro, но вы можете воспользоваться стандартными инструментальными средствами, входящими в дистрибутивный пакет этой базы данных (pgAdmin версии 3 или 4)
В листинге 2.1 приведен полный исходный код приложения. Я всегда стараюсь предоставить настолько полный код, насколько это возможно, включая инструкции import, чтобы вы не ошибались, используя неправильные пакеты или устаревшие классы с теми же именами. Этот код можно загрузить из репозитория на сайте GitHub: https://github.com/jgperrin/net.jgp.books.spark.ch02. Листинг 2.1 Потребление данных в формате CSV, преобразование и сохранение результата в базе данных package net.jgp.books.spark.ch02.lab100_csv_to_db; import static org.apache.spark.sql.functions.concat; import static org.apache.spark.sql.functions.lit; import java.util.Properties; import import import import
org.apache.spark.sql.Dataset; org.apache.spark.sql.Row; org.apache.spark.sql.SaveMode; org.apache.spark.sql.SparkSession;
Глава 2 Архитектура и рабочий процесс
60
public class CsvToRelationalDatabaseApp { public static void main(String[] args) { CsvToRelationalDatabaseApp app = new CsvToRelationalDatabaseApp(); app.start(); } private void start() { SparkSession spark = SparkSession.builder() .appName("CSV to DB") .master("local") .getOrCreate(); Dataset df = spark.read() .format("csv") .option("header", "true") .load("data/authors.csv"); df = df.withColumn( "name", concat(df.col("lname"), lit(", "), df.col("fname"))); String dbConnectionUrl = "jdbc:postgresql://localhost/spark_labs"; Properties prop = new Properties(); prop.setProperty("driver", "org.postgresql.Driver"); prop.setProperty("user", "jgp"); prop.setProperty("password", "Spark. Параметр --help позволяет получить справочную информацию. Вы должны увидеть следующий вывод: To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use ➥ setLogLevel(newLevel). Spark context Web UI available at http://un.oplo.io:4040 Spark context available as 'sc' ➥ (master = local[*], ➥ app id = local-1534641339137). Spark session available as 'spark'. Welcome to ____ __ / __/__ ___ _____/ /__ _\ \/ _ \/ _ `/ __/ '_/ /___/ .__/\_,_/_/ /_/\_\ version 2.3.1 /_/
❶ ❷ ❸
159
Взаимодействие со Spark Using Scala version 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_181) Type in expressions to have them evaluated. Type :help for more information. scala> ❶ Командная оболочка инициализируется с экземпляром класса SparkContext с именем sc. ❷ Работа в локальном режиме на всех ядрах локального компьютера.
❸ Экземпляр сеанса SparkSession доступен как spark.
Необходим как минимум один рабочий узел, который может находиться на том же физическом узле, что и ведущий узел
Элементы Spark
Узел командной оболочки, ведущий и рабочий узлы могут размещаться на одном и том же физическом узле
Рис. 5.9 Стек Spark при работе в интерактивном режиме похож на режим кластера. Единственное различие состоит в способе начала рабочего сеанса
Разумеется, для продолжения работы в командной оболочке необходимо знать язык Scala, но этого не требуется в контексте данной книги (в приложении J приведена немного более подробная информация об этом). Далее в этом подразделе будут рассматриваться простые операции Scala, и вы увидите сходство с Java. Если вы хотите выйти из командной оболочки прямо сейчас (я вас понимаю), то нажмите комбинацию клавиш Ctrl+C. Но можно кое-что попробовать, например вывести версию Spark:
Глава 5 Создание простого приложения для развертывания
160
scala> sc.version res0: String = 2.3.1
или scala> spark.sparkContext.version res1: String = 2.3.1
Так как темой этой главы является приближенное вычисление π, рассмотрим, как это можно сделать в интерактивной командной оболочке. Ниже приведен фрагмент кода Scala, который вы можете ввести в командной оболочке: import scala.math.random val slices = 100 val n = (100000L * slices).toInt val count = spark.sparkContext.parallelize(1 until n, slices).map { i => val x = random * 2 - 1 val y = random * 2 - 1 if (x*x + y*y . Параметр --help позволяет получить справочную информацию. Вы должны увидеть следующий вывод: Python 2.7.15rc1 (default, Apr 15 2018, 21:51:34) [GCC 7.3.0] on linux2 Type "help", "copyright", "credits" or "license" for more information. 2018-10-01 06:35:23 WARN NativeCodeLoader:62 - Unable to load ➥ native-hadoop library for your platform... using builtin-java classes ➥ where applicable Setting default log level to "WARN". To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use ➥ setLogLevel(newLevel). Welcome to ____ __ / __/__ ___ _____/ /__ _\ \/ _ \/ _ `/ __/ '_/ /__ / .__/\_,_/_/ /_/\_\ version 2.3.1 /_/ Using Python version 2.7.15rc1 (default, Apr 15 2018 21:51:34) SparkSession available as 'spark'. >>>
❶
❷
❶ Командная оболочка использует версию Python 2, установленную в конкретной системе, здесь
это версия v2.7.15rcl.
❷ Экземпляр сеанса SparkSession доступен как spark.
162
Глава 5 Создание простого приложения для развертывания
Для выхода из командной оболочки используйте комбинацию клавиш Ctrl+D или введите команду quit(). Если предпочитаете работать с версией Python v3, то перед запуском командной оболочки PySpark установите для переменной среды PYSPARK_PYTHON значение python3: $ export PYSPARK_PYTHON=python3 $ ./pyspark
Тогда вывод будет таким: ❶
Python 3.6.5 (default, Apr 1 2018, 05:46:30) [GCC 7.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. 2018-10-01 06:40:22 WARN NativeCodeLoader:62 - Unable to load ➥ native-hadoop library for your platform... using builtin-java classes ➥ where applicable Setting default log level to "WARN". To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use ➥ setLogLevel(newLevel). Welcome to ____ __ / __/__ ___ _____/ /__ _\ \/ _ \/ _ `/ __/ '_/ /__ / .__/\_,_/_/ /_/\_\ version 2.3.1 /_/ Using Python version 3.6.5 (default, Apr 1 2018 05:46:30) SparkSession available as 'spark'. >>>
❶ Теперь командная оболочка использует версию Python 3, установленную в конкретной системе,
здесь это версия v3.6.5.
Далее в этом разделе предполагается использование Python v3. вам потребуются некоторые знания о языке Python. Можно вывести версию Spark: >>> spark.version '2.3.1'
Приближенное вычисление π на языке Python можно выполнить следующим образом: import sys from random import random from operator import add from pyspark.sql import SparkSession spark = SparkSession\ .builder\ .appName("PythonPi")\ .getOrCreate() n = 100000 def throwDarts(_):
❶
163
Резюме x = random() * 2 - 1 y = random() * 2 - 1 return 1 if x ** 2 + y ** 2 >> import sys >>> from random import random >>> from operator import add >>> from pyspark.sql import SparkSession >>> >>> spark = SparkSession\ ... .builder\ ... .appName("PythonPi")\ ... .getOrCreate() >>> n = 100000 >>> def throwDarts(_): ... x = random() * 2 - 1 ... y = random() * 2 - 1 ... return 1 if x ** 2 + y ** 2 >> count = spark.sparkContext.parallelize(range(1, n + 1), ➥ 1).map(throwDarts).reduce(add) >>> print("Pi is roughly %f" % (4.0 * count / n)) Pi is roughly 3.138000 >>> spark.stop() >>>
Если необходимо узнать больше о языке Python, то рекомендую книгу «The Quick Python Book», автор Наоми Седер (Naomi Ceder) (Manning, 2018), сейчас вышло третье издание этой книги: www.manning.com/ books/the-quick-python-book-third-edition).
Резюме Spark может работать без потребления данных, он может генерировать собственные данные. Spark поддерживает три режима выполнения: локальный, режим кластера и интерактивный режим. Локальный режим позволяет разработчикам начать разработку с использованием Spark буквально за минуты.
Глава 5 Создание простого приложения для развертывания
164
Режим кластера используется в производственной эксплуатации. Можно передать задание в Spark или установить соединение с ведущим узлом. Приложением-драйвером является та программа, в которой есть метод main(). Ведущему узлу известны все рабочие узлы. Всю основную работу выполняют рабочие узлы. Spark обеспечивает распределение приложения в пакете JAR в режиме кластера – на каждый рабочий узел. MapReduce – широко распространенный метод работы с большими данными в распределенных системах. Hadoop – самая известная реализация этого метода. Spark скрывает сложности Hadoop. Непрерывная интеграция и непрерывная доставка (CICD) – гибкая методология, поощряющая частую интеграцию и доставку. Лямбда-функции, введенные в Java 8, позволяют создавать функции вне области видимости класса. Файл uberJAR содержит все классы (включая зависимости) приложения в одном файле. Maven может автоматически создавать файл uberJAR. Maven может развертывать исходный код одновременно с файлом uberJAR. Операции отображения и свертки в Spark могут использовать классы или лямбда-функции. Spark предоставляет веб-интерфейс для анализа выполнения заданий и приложений. Интерактивный режим позволяет вводить команды на языках Scala, Python или R непосредственно в командной оболочке. Интерактивности также можно достичь с помощью виртуальных блокнотных сред, таких как Jupyter или Zeppelin. Число π можно приблизительно вычислить методом бросков дротиков в мишень для дартс и измерений отношения дротиков внутри и вне круга.
6
Развертывание простого приложения
Краткое содержание главы: развертывание приложения Spark; определение ролей самых важных компонент в кластерной среде Spark; выполнение приложения в кластере; вычисление приближенного значения числа π с использованием Spark; анализ журналов выполнения.
В предыдущих главах вы узнали, что такое Apache Spark, как создавать простые приложения и, как я надеюсь, поняли основные концепции, такие как фрейм данных и механизм ленивых (отложенных) вычислений. Эта глава связана с предыдущей: в главе 5 было создано приложение, а в этой главе будет выполняться его развертывание. Изучение главы 5 перед чтением этой главы не требуется, но настоятельно рекомендуется. В этой главе мы немного отступим от темы написания кода для приложений, для того чтобы узнать, как нужно взаимодействовать со Spark для организации развертывания и производственной эксплуатации приложений. Может возникнуть вопрос: «Почему мы обсуждаем процесс развертывания так рано в этой книге? Ведь развертывание выполняется в самом конце, не так ли?» Чуть более 20 лет назад, когда я писал приложения на Visual Basic 3 (VB3) и приближался к завершению очередного проекта, необходимо было запустить Мастер настройки Visual Basic Setup Wizard, который должен был помочь в создании дистрибутивных 3.5-дюймовых флоппи-дисков. В то время моей настольной книгой, почти Библией, было руководство программиста Microsoft Visual Basic 3.0 Programmer’s Guide, содержащее 25 глав, а процедура развертывания приложения описывалась в главе 25.
166
Глава 6 Развертывание простого приложения
Вернемся в наши дни. Ваш магазин использует DevOps или что-то вроде этого, и, возможно, вы встречались с такими терминами, как непрерывная интеграция и непрерывная доставка (continuous integration and continuous delivery – CICD), а процедура развертывания в наше время выполняется на гораздо более раннем этапе общего процесса, чем это было когда-то. В одном из моих последних проектов группа разработки реализовала прототип конвейера данных с использованием Spark, и методика CICD являлась полноценной частью реализации этого прототипа. Процедура развертывания важна. Понимание ограничений процедуры развертывания чрезвычайно важно, и я настоятельно рекомендую уделять особое внимание процедуре развертывания как можно раньше в любом проекте.
Непрерывная интеграция и непрерывное развертывание (доставка) CICD или CI/CD – это сокращенное обозначение объединенных практических методик непрерывной интеграции и непрерывной доставки (программных приложений). Непрерывная интеграция (Continuous integration – CI) – это практическая методика объединения (слияния) всех рабочих копий разработчиков в совместно используемую главную (магистральную) ветвь с частыми временны́ми интервалами. Объединение может выполняться несколько раз в день. Грэди Буч (Grady Booch) (сооснователь языка UML, сотрудник IBM, лауреат премии Тьюринга 2007 г. и т. д.) сформулировал принципы CI в своей методике инженерии программного обеспечения в 1991 году. В методике экстремального программирования (extreme programming – XP) концепция CI получила дальнейшее развитие, и утверждалась необходимость интеграции более одного раза в день. Главная цель методики CI – предотвращение проблем при интеграции. Методика CI предназначена для использования в совокупности с автоматизированными модульными тестами (unit tests), разработанными благодаря методике разработки, управляемой тестами (test-driven development – TDD). Изначально эта методика проектировалась как исполнение и успешное завершение всех модульных тестов в локальной среде конкретного разработчика перед слиянием его экземпляра рабочей копии с главной ветвью. Такой подход помогал защитить непрерывно продолжающуюся работу одного разработчика от разрушения копией другого разработчика. Самые последние разработки этой концепции вводят в использование серверы сборки (build servers), которые автоматически выполняют модульные тесты с регулярными интервалами или даже после каждой передачи кода (commit) и сообщают результаты тестирования разработчикам. Непрерывная доставка (Continuous delivery – CD) позволяет группам разработчиков создавать программное обеспечение в коротких циклах, обеспечивая требуемую надежность программного обеспечения, вводимого в эксплуатацию в любое время. Методика непрерывной доставки ориентирована на сборку, тестирование и выпуск (ввод в эксплуатацию) программ-
Развертывание простого приложения
167
ного обеспечения с значительно увеличенной скоростью и частотой. Такой подход помогает сократить затраты, время и риск при доставке изменений (обновлений), позволяя постепенно обновлять приложения, находящиеся в производственной эксплуатации. Простой и понятный, повторно воспроизводимый без затруднений процесс развертывания важен для непрерывной доставки. Непрерывную доставку (continuous delivery) иногда путают с непрерывным развертыванием (continuous deployment). При непрерывном развертывании любое изменение в производстве, которое успешно проходит последовательность тестов, автоматически развертывается в эксплуатационной среде. В отличие от этого при непрерывной доставке программное обеспечение требует надежной версии-релиза в любое время, но решение по вводу в эксплуатацию принимает человек обычно на основе бизнес-факторов. Оба определения с небольшими изменениями взяты из «Википедии».
Таким образом, в отличие от меня, работавшего в 1994 году с VB3, вы начали изучать процесс развертывания в главе 5. Но не стоит беспокоиться: традиция соблюдается, так как подробное описание процесса развертывания (включая управление кластерами, ресурсами, совместно используемыми файлами и прочими объектами) все-таки находится в главе 18. Сначала мы рассмотрим пример, в котором данные генерируются внутри Spark, исключая необходимость потребления данных. Потребление данных с передачей их в кластер организовано немного сложнее, чем создание собственного сгенерированного набора данных. Затем мы продолжим изучение трех способов взаимодействия со Spark: 1 локального режима (local mode), с которым вы уже знакомы на примерах из предыдущих глав; 2 режима кластера (cluster mode) (с использованием более одного компьютера или узла); 3 интерактивного режима (interactive mode) (через командную оболочку). Вы настроите программную среду для лабораторной работы. Потом будут рассматриваться ограничения, характерные для процесса распределения вычислительных ресурсов по нескольким узлам. Важно накопить этот опыт именно сейчас, чтобы вы были лучше подготовлены к планированию развертывания реальных приложений. Наконец, приложение будет запущено и выполнено в кластере. ЛАБОРАТОРНАЯ РАБОТА Примеры в этой главе связаны с примерами из главы 5, поэтому включены в один и тот же репозиторий. Код примеров и вспомогательные материалы доступны на сайте GitHub в репозитории https://github.com/jgperrin/net.jgp. books.spark.ch05.
168
6.1
Глава 6 Развертывание простого приложения
Подготовка к изучению примера: роль компонент В предыдущей главе вы узнали, как вычислить приближенное значение числа π, используя Spark с применением классов и лямбда-функций. Было выполнено соответствующее приложение, но на самом деле мы не рассматривали, что происходило внутри инфраструктуры, и не обращали внимания на роль каждого элемента архитектуры. Компонента (component) – это логическое представление, включающее в себя набор взаимосвязанных функций. С физической точки зрения компонента может быть пакетом, веб-сервисом или чем-то другим. Главное преимущество идентификации компоненты состоит в том, что можно более просто идентифицировать ее интерфейс, который является способом обмена информацией с ней. Во вводной части главы вы узнаете о трех способах взаимодействия со Spark. Но вне зависимости от того, работаем ли мы в локальном, кластерном или интерактивном режиме, Spark использует определенный набор компонент. Роль каждой компоненты отличается от других, компоненты не дублируют друг друга. Важно понимать, что происходит с каждой компонентой, чтобы получить возможность без затруднений отлаживать или оптимизировать рабочие процессы. Сначала предлагается краткий обзор компонент и взаимодействий между ними, затем каждая компонента рассматривается более подробно.
6.1.1 Краткий обзор компонент и взаимодействий между ними В этом подразделе предлагается высокоуровневый обзор компонент архитектуры Spark, а также связей между ними. Будет рассматриваться рабочий поток (процесс) на основе примера приложения из главы 5, которое вычисляет приближенное значение π. На рис. 6.1 показаны позиции компонент в схеме архитектуры. С точки зрения приложения единственное соединение устанавливается при создании сеанса на ведущем узле / в диспетчере кластера. На рис. 6.1 это соединение помечено числом 1. В табл. 6.1 описаны все связи (соединения). В столбце «Уровень внимания» объясняется, почему вы должны уделить внимание каждому конкретному элементу архитектуры Spark: эта информация будет полезной при организации защиты, отладки и развертывания Spark.
Подготовка к изучению примера: роль компонент
169
Это компонента, которая устанавливается как «ведущий узел» при создании сеанса
Код приложения
Вы получаете контекст SparkContext при создании сеанса SparkSession
Вычислительный кластер (состоящий из узлов)
Рис. 6.1 Компоненты Spark и взаимодействия между ними. Числами обозначен наиболее вероятный порядок сетевых вызовов, инициализирующих компоненты
Таблица 6.1 Связи между компонентами Spark Связь Исходный (соединение) пункт 1 Драйвер
Целевой пункт Диспетчер кластера / ведущий узел Исполнитель
2
Диспетчер кластера / ведущий узел
3
Исполнитель
Исполнитель
4
Исполнитель
Драйвер
Уровень внимания Этой связи необходимо уделить внимание: этим способом приложение устанавливает соединение с ведущим узлом или диспетчером кластера Эта связь устанавливает соединение между рабочими узлами и ведущим узлом. Рабочие узлы инициализируют соединение, но данные передаются от ведущего узла на рабочие узлы. Если эта связь нарушена, то диспетчер кластера не сможет обмениваться информацией с исполнителями Внутренняя связь между исполнителями. Разработчикам нет необходимости уделять какое-либо внимание этой связи Исполнителю необходима возможность обращения к драйверу, это означает, что драйвер на должен быть защищен сетевым экраном (firewall) (эту ошибку часто допускают новички, когда первое написанное ими приложение пытается установить соединение с кластером в облачной среде). Если исполнители лишены возможности обмена информацией с драйвером, то они не смогут передать данные обратно в приложение
Глава 6 Развертывание простого приложения
170
В листинге 6.1 показан код приложения, которое вы изучали в главе 5, когда вычисляли приближенное значение π. В это главе я не буду объяснять, что делает это приложение, вместо этого мы рассмотрим, какие компоненты используются/активизируются приложением. Этот код будет работать на узле драйвера, но он управляет процессами и генерирует действия на других узлах. Номера связей в листинге 6.1 соответствуют номерам связей на рис. 6.1. ЛАБОРАТОРНАЯ РАБОТА Это лабораторная работа #200 из главы 5. Она доступна на сайте GitHub в репозитории https://github. com/jgperrin/net.jgp.books.spark.ch05. Листинг 6.1
Вычисление приближенного значения числа π
package net.jgp.books.spark.ch05.lab200_pi_compute_cluster; … public class PiComputeClusterApp implements Serializable { … private final class DartMapper implements MapFunction { … } private final class DartReducer implements ReduceFunction { … } public static void main(String[] args) { PiComputeClusterApp app = new PiComputeClusterApp(); app.start(10); } private void start(int slices) { int numberOfThrows = 100000 * slices; … SparkSession spark = SparkSession .builder() .appName("JavaSparkPi on a cluster") .master("spark://un:7077") .config("spark.executor.memory", "4g") .getOrCreate(); … List l = new ArrayList(numberOfThrows); for (int i = 0; i < numberOfThrows; i++) { l.add(i); } Dataset incrementalDf = spark .createDataset(l, Encoders.INT()) .toDF(); … Dataset dartsDs = incrementalDf .map(new DartMapper(), Encoders.INT()); … int dartsInCircle = dartsDs.reduce(new DartReducer());
⎫
⎪
⎬
⎪ ⎪
❶
⎭
⎫
⎬ ⎭
❷
⎫ ❸ ⎭ ❹
Подготовка к изучению примера: роль компонент
171
… System.out.println("Pi is roughly " + 4.0 * dartsInCircle / numberOfThrows); spark.stop(); } } ❶ Связь 1: сеанс размещается в диспетчере кластера. ❷ Связь 2: первый фрейм данных создается в исполнителе. ❸ Этот шаг добавляется в направленный ациклический граф, который находится в диспетчере клас-
тера.
❹ Связь 4: итог операции приведения к общему результату передается обратно в приложение.
Приложения Spark работают как независимые процессы в кластере. Объект SparkSession в приложении (приложение также называют драйвером или программой-драйвером) координирует рабочие процессы. Для каждого конкретного приложения создается собственный, единственный в своем роде объект SparkSession независимо от того, работаете ли вы в локальном режиме или в кластере с 10 000 узлов. Объект SparkSession создается при создании конкретного сеанса, как показано ниже: SparkSession spark = SparkSession.builder() .appName("An app") .master("local[*]") .getOrCreate();
Вы также получаете контекст SparkContext как часть созданного сеанса. Контекст был единственным способом работы со Spark до версии v2. Сейчас по большей части нет необходимости взаимодействовать со SparkContext, но если потребуется (для доступа к информации об инфраструктуре, для создания аккумуляторов и прочих подобных операций, описанных в главе 17), то можно получить доступ к контексту, как показано ниже: SparkContext sc = spark.sparkContext(); System.out.println("Running Spark v" + sc.version());
По существу, диспетчер кластера распределяет ресурсы между приложениями. Но для работы в кластере сеанс SparkSession может устанавливать соединения с несколькими типами диспетчеров кластера. Тип диспетчера кластера может определяться конкретной инфраструктурой, инженерами-архитекторами уровня предприятия или всезнающим гуру. Здесь у вас нет выбора. В главе 18 рассматривается несколько вариантов диспетчеров кластера, в том числе YARN, Mesos и Kubernetes. После установления соединения Spark получает в свое распоряжение исполнителей на узлах в кластере. Исполнители – это процессы виртуальной машины Java (JVM), которые выполняют вычисления и сохраняют данные для приложения. На рис. 6.2 показано распределение ресурсов диспетчером кластера. Далее диспетчер кластера передает код приложения исполнителям. Вам не нужно заботиться о развертывании приложения на каждом узле. Наконец, сеанс SparkSession передает задачи (tasks) исполнителям для выполнения.
172
Глава 6 Развертывание простого приложения
Ведущий узел передает задачи на доступные узлы
На этих рабочих узлах нет доступных ресурсов
Рис. 6.2 Одна из ролей диспетчера кластера – поиск ресурсов на рабочих узлах
6.1.2 Рекомендации по устранению проблем в архитектуре Spark Архитектура Spark, описанная в разделе 6.1.1, может показаться необычной, но, надеюсь, при этом остается простой для понимания, по крайней мере, на том уровне, на котором инженеры по обработке данных и по программному обеспечению должны ее понимать (тонкая настройка производительности, несомненно, потребует более глубоких знаний). В этом разделе мы рассмотрим подробности архитектуры и присущие ей ограничения. Чаще всего могут возникать следующие проблемы: Spark выполняет работу слишком долго или вы вообще никогда не получаете ожидаемые результаты. Если что-то пошло не так после развертывания, то следует рассмотреть следующие варианты: даже если заданное действие не возвращает результаты в приложение, что случается при экспорте данных, вы всегда должны быть уверены в том, что исполнитель может обмениваться информацией с драйвером. Обмен информацией с драйвером означает, что исполнитель и драйвер не должны быть разделены защитным сетевым экраном (firewall), не должны находиться в разных сетях, предъ-
Подготовка к изучению примера: роль компонент
173
являя многочисленные IP-адреса и т. п. Эти проблемы при обмене информацией могут возникать, когда приложение запускается локально (например, в процессе разработки) и пытается установить соединение с удаленным кластером. Программа-драйвер непременно должна находиться в режиме прослушивания и принимать входящие соединения от своих исполнителей на протяжении всего жизненного цикла (см. spark.driver.port в разделе «Конфигурирование приложения» в приложении К); каждое приложение получает в свое распоряжение собственные процессы исполнителей, которые остаются активными все время, пока работает это приложение, и выполняют задачи в нескольких потоках (threads). Это дает преимущество, заключающееся в изоляции приложений друг от друга, как на стороне планирования (каждый драйвер планирует собственные задачи), так и на стороне исполнителя (задачи от различных приложений выполняются в различных виртуальных машинах JVM). Но это также означает, что не могут совместно использоваться различными приложениями Spark (различными экземплярами SparkSession или SparkContext) без обязательной записи их во внешнюю систему хранения данных; Spark нейтрален по отношению к диспетчеру кластера, находящемуся на более низком уровне, пока может получать в свое распоряжение процессы исполнителей, которые обмениваются информацией друг с другом. Возможен запуск в диспетчере кластера, который поддерживает другие приложения, например Mesos или YARN (см. главу 18); поскольку драйвер планирует задачи в кластере, он должен функционировать физически близко к рабочим узлам, предпочтительнее всего, в одной и той же локальной сети. Процессы весьма интенсивно используют сеть, поэтому при расположении физических сетевых узлов как можно ближе друг к другу сокращаются задержки в сети. Совместное обслуживание физических сетевых узлов организовать не так-то просто, или может потребоваться использование облачных сервисов. Если вы планируете работать со Spark в облачной среде, то договоритесь с оператором своей облачной среды о выделении для вас компьютеров, расположенных физически близко друг к другу. В приложении R перечислены наиболее часто возникающие проблемы и их решения, а также источники информации, в которых можно получить помощь.
6.1.3 Дополнительная информация для изучения В разделе 6.1 была представлена архитектура Spark как минимальная чрезвычайно важная информация, необходимая для процесса развертывания. Разумеется, существуют и более полные источники информации по этой теме. В начале этой книги перечислены термины, которыми оперирует программа-драйвер во время выполнения конкретных приложений. Чтобы узнать об этом более подробно, можно обратиться к официальной доку-
174
Глава 6 Развертывание простого приложения
ментации Spark, доступной на сайте https://spark.apache.org/docs/latest/ cluster-overview.html.
6.2
Создание кластера В разделе 6.1 рассматривалось создание приложения без процедуры потребления данных, а также три способа взаимодействия со Spark, и были описаны различные компоненты Spark и связи между ними. Все это должно стать хорошей основой для следующей задачи: развертывание приложения в реальном кластере. В этом разделе вы узнаете, как выполнить следующие шаги: создание кластера; настройку среды кластера; развертывание приложения (с помощью создания файла uberJAR или с использованием Git и Maven); запуск приложения; анализ журналов выполнения.
6.2.1 Создание собственного кластера Я прекрасно понимаю, что совсем не просто создать и настроить распределенную среду дома или в офисе, но, как вам уже известно, Spark предназначен для работы в распределенной среде. В этом разделе я буду описывать возможные варианты, некоторые более реалистичные по сравнению с другими – это зависит от вашего времени и бюджета. Здесь будет рассматриваться развертывание с использованием четырех узлов, но вы можете работать на единственном узле, если так удобнее. Настоятельно рекомендую организовать хотя бы два узла – это позволит лучше понять работу в сети и методику совместного использования данных, конфигурации и бинарных файлов (приложения, файлов JAR). Итак, какие варианты возможны для организации работы в кластере? Для создания распределенной среды в домашних условиях предлагаются следующие варианты: вероятно, самый простой вариант – использование облачной среды: приобрести две-три виртуальные машины у облачного провайдера – Amazon EC2, IBM Cloud, OVH или Azure. Следует отметить, что стоимость этого варианта, возможно, трудно будет оценить. Я не рекомендую пользоваться Amazon EMR для нашего случая, так как в этой облачной среде существуют некоторые ограничения (более подробно о них вы узнаете в главе 18). Вам не понадобятся сверхмощные серверы – достаточно будет 8 Гб или немного больше оперативной памяти и 32 Гб на диске. Мощность процессора не имеет значения для выполнения лабораторной работы в этой главе; второй вариант – наличие дома чуть более мощного компьютера, больше похожего на настоящий сервер, на котором будут установлены виртуальные машины или контейнеры. В этом варианте требования практически такие же, как для каждого компьютера из первого варианта, – это означает наличие 32 Гб оперативной памя-
175
Создание кластера
ти на физической машине, если планируется создание четырех узлов. Этот вариант можно реализовать практически бесплатно, если воспользоваться контейнерами Docker или виртуальной машиной VirtualBox. Совет: игровой компьютер ваших детей, используемый для онлайновой игры Fortnite, вероятно, является подходящей кандидатурой для Spark, к тому же можно использовать его графический процессор (GPU) для выполнения каких-нибудь полезных операций, например TensorFlow в Spark; третий вариант – использование всей старой компьютерной аппаратуры, которая найдется в доме, для создания кластера, исключая компьютеры, в которых меньше 8 Гб оперативной памяти. Абсолютно не подходят для этого Atari 800XL, Commodore 64, ZX81 и некоторые другие старые модели; наконец, вы можете выбрать мой вариант – купить и создать четыре узла с нуля. Мой кластер называется CLEGO, а руководство по его созданию (и объяснение его названия) вы можете найти в моем блоге http://jgp.net/clego. В этой главе я буду использовать четыре узла кластера CLEGO как аппаратуру, специально предназначенную для распределенной обработки. На рис. 6.3 показана архитектура, используемая в этой лабораторной работе. Узел #1 hostname: un FQDN: un.oplo.io IP: 10.0.100.81
Узел #2 hostname: deux FQDN: deux.oplo.io IP: 10.0.100.82
Узел #3 hostname: trois FQDN: trois.oplo.io IP: 10.0.100.83
Узел #4 hostname: quatre FQDN: quatre.oplo.io IP: 10.0.100.84
Физические узлы, часть кластера
Рабочие узлы также называют ведомыми (slave) узлами; этот термин постепенно выходит из употребления. Иногда вы будете встречать его в некоторых инструментах командной строки
Логические узлы с соответствующими функциями в кластере
Рис. 6.3 Архитектура, используемая для развертывания в рамках лабораторной работы этой главы: используются четыре узла. Хосты названы un, deux, trios, quatre (французские числительные один, два, три, четыре). FQDN – аббревиатура, означающая fully qualified domain name (полностью определенное имя домена)
176
Глава 6 Развертывание простого приложения
Если же у вас нет возможности использования более одного узла, то вы все равно можете продолжить работу и выполнять требуемые операции только на одном узле un.
6.2.2 Настройка среды кластера После определения рабочей среды необходимо выполнить следующие процедуры: установку Spark; конфигурирование и запуск Spark; загрузку/выгрузку приложения; запуск приложения. Необходимо установить Spark на каждом узле (в приложении К описаны подробности установки). Установка выполняется чрезвычайно просто. Нет необходимости устанавливать приложение на каждом узле. Далее в этой главе предполагается, что Spark установлен в каталоге /opt/ apache-spark. На ведущем узле (в рассматриваемом здесь примере это узел un) необходимо перейти в каталог /opt/apache-spark/sbin. Запустить ведущий узел: $ ./start-master.sh
Напомню, что ведущий узел не выполняет большого объема работы, но ему постоянно требуются рабочие узлы. Для запуска первого рабочего узла выполняется следующая команда: $ ./start-slave.sh spark://un:7077
В этом варианте рабочий узел запускается на том же физическом узле, что и ведущий узел. БУДЬТЕ ВНИМАТЕЛЬНЫ ПРИ КОНФИГУРИРОВАНИИ СЕТИ При создании кластера сеть играет чрезвычайно важную роль. Каждый узел должен иметь возможность обмениваться информацией со всеми другими узлами в обоих направлениях. Необходимо проверить и убедиться в том, что требуемые порты доступны и не используются кем-то еще, обычно это порты 7077, 8080 и 4040. Эти порты не будут открываться в интернет, только внутри локальной сети. Проверку можно выполнить с помощью утилит ping, telnet (используя команду telnet ). Не используйте localhost как имя хоста в любой из этих команд. Первым всегда запускается ведущий узел, затем рабочие узлы. Чтобы проверить, что все работает правильно, откройте браузер и перейдите по адресу http://un:8080/. Это веб-интерфейс, предоставляемый Spark. При этом не требуется запускать веб-сервер или устанавливать связь веб-сервера со Spark. Убедитесь в том, что никакая программа не работает с портом 8080, или измените конфигурацию соответствующим образом. На рис. 6.4 показан результат соединения.
Создание кластера
177
Только что созданный рабочий узел активен и зарегистрирован на только что созданном ведущем узле
Рис. 6.4 Для ведущего узла имеется единственный рабочий узел. Здесь также можно видеть отсутствие работающих или завершенных приложений
При запуске приложений это окно интерфейса будет автоматически заполняться соответствующей информацией, и вы получите возможность просматривать больше сведений о приложениях, о ходе их выполнения и т. п. В разделе 6.4.1 вы узнаете, как получить доступ к журналам (logs) приложения. Теперь можно перейти к следующему узлу (в нашем примере это узел deux). Снова перейдите в каталог /opt/apache-start/sbin. Еще один ведущий узел запускать не нужно, но необходимо активизировать второй рабочий узел: $ ./start-slave.sh spark://deux:7077
Теперь можно обновить окно браузера. На рис. 6.5 показан результат. Так как всего используется четыре узла, я повторю эту операцию для третьего и четвертого рабочих узлов. Ведущий узел работает на том же физическом узле, что и первый рабочий узел. После завершения всех операций окно браузера должно выглядеть так, как показано на рис. 6.6. Теперь у нас имеется работающий кластер, состоящий из одного ведущего узла и четырех рабочих узлов, готовых к выполнению заданий. Физический кластер использует четыре узла.
178
Глава 6 Развертывание простого приложения Первый рабочий узел остается активным и зарегистрированным на ведущем узле
Появился второй рабочий узел, который также зарегистрирован на ведущем узле
Рис. 6.5 На панели управления Spark теперь показаны два рабочих узла Первый рабочий узел зарегистрирован на ведущем узле
Четвертый рабочий узел зарегистрирован на ведущем узле
Второй рабочий узел зарегистрирован на ведущем узле
Третий рабочий узел зарегистрирован на ведущем узле
Рис. 6.6 Теперь на панели управления Spark показаны все четыре рабочих узла
Создание приложения для работы в кластере
6.3
179
Создание приложения для работы в кластере Наша работа близка к завершению. Вы развернули Spark и создали кластер. Я почти уверен, что вы с нетерпением ждете начала этапа развертывания кода приложения для вычисления приближенного значения π в кластере и хотите побыстрее увидеть, как оно выполняется. Но умерьте немного свой пыл – сначала необходимо организовать развертывание кода в кластере. Для развертывания приложения существует несколько вариантов: создание файла uberJAR с кодом приложения и всех необходимых зависимостей; создание архивного файла JAR с приложением и обеспечение размещения всех требуемых зависимостей на каждом рабочем узле (этот вариант не рекомендуется); клонирование/извлечение кода из репозитория системы управления исходным кодом.
SPARK РАЗВЕРТЫВАЕТ КОД ПРИЛОЖЕНИЯ НА РАБОЧИХ УЗЛАХ Это весьма полезная и удобная функциональная возможность. Пользователь должен развернуть код приложения только один раз, а созданием копий на каждом рабочем узле Spark займется сам. Выбор между вариантом создания файла uberJAR и загрузкой исходного кода из репозитория Git и локальной сборкой, вероятно, остается за подразделением, которое отвечает за развертывание и поддержку инфраструктуры в вашей организации. На выбор может влиять стратегия обеспечения безопасности, например «никакой компиляции на корпоративных рабочих серверах».
Работа с данными Процедуру развертывания конкретного приложения на каждом узле Spark выполняет сам с ведущего узла. Но Spark не может обеспечить полную уверенность в том, что все исполнители получают доступ к данным. Напомню, что в процессе, описываемом в этой главе, не развертываются никакие данные, так как Spark сам генерирует фреймы данных, содержащие данные для вычисления значения π. При работе с внешними данными всем рабочим узлам потребуется доступ к этим данным. Hadoop Distributed File System (HDFS) – это распределенная файловая система, которую весьма часто выбирают для совместного использования данных с возможностью их репликации. Для развертывания данных можно использовать следующие варианты:
совместно используемый накопитель, доступный для всех рабочих узлов, например Server Message Block/Common Internet File System (SMB/CIFS), Network File System (NFS) и многие другие. Настоятельно рекомендуется создавать одинаковую точку монтирования для каждого рабочего узла;
Глава 6 Развертывание простого приложения
180
сервис совместного использования файлов, такой как Nextcloud/ownCloud, Box, Dropbox или любой другой. При этом будет обеспечена автоматическая репликация данных на каждый рабочий узел. Это решение ограничивает возможности передачи данных: данные копируются только один раз. Как и в варианте с совместно используемым накопителем, настоятельно рекомендуется создавать единую точку монтирования для каждого рабочего узла; распределенная файловая система, например HDFS.
Эти методики и технологии более подробно будут рассматриваться в главе 18.
6.3.1 Создание файла uberJAR для приложения При изучении возможных способов развертывания одним из предлагаемых вариантов является упаковка приложения в файл uberJAR. Если вспомнить содержимое главы 5, uberJAR – это архивный файл, содержащий все классы, необходимые приложению, независимо от количества JAR-файлов, указанных в пути к классу. Файл uberJAR содержит большинство, если не все требуемые зависимости для приложения. Благодаря такому подходу логистика сверх(uber)упрощена, так как необходимо работать только с одним JAR-файлом. Рассмотрим создание такого файла uberJAR с помощью Maven. Для создания файла uberJAR будет использоваться подключаемый модуль Maven Shade. С полным комплектом документации по этому подключаемому модулю можно ознакомиться на сайте http://maven.apache. org/plugins/maven-shade-plugin/index.html. Откройте файл проекта pom.xml. Найдите раздел build/plugins и добавьте в него содержимое листинга 6.2. Листинг 6.2 Использование подключаемого модуля Shade для создания файла uberJAR с помощью Maven
…
org.apache.maven.plugins maven-shade-plugin 3.1.1
package
shade
true
⎫ ⎬ ⎭
❶ ❷
❸
181
Создание приложения для работы в кластере
org.apache.spark org.apache.hadoop
❹
… junit:junit jmock:* *:xml-apis log4j:log4j:jar:
true uber
❶ ❷ ❸ ❹ ❺ ❻
❺ ❻
Определение подключаемого модуля. Подключаемый модуль Shade будет выполнен во время упаковки (при вызове пакета mvn). Удаление всех классов, которые не используются в этом проекте, сокращение размера файла JAR. Исключения. Разрешение использования суффикса для имени файла uberJAR. Суффикс, добавляемый к генерируемому файлу uberJAR.
Исключения (exclusions) чрезвычайно важны – вы не должны заботиться обо всех требуемых зависимостях. При отсутствии исключений все классы зависимостей будут переданы в создаваемый файл uberJAR, т. е. в него будут включены все классы и артефакты Spark. Разумеется, они необходимы, но поскольку уже включены в Spark, то будут доступными на целевой системе. Если включить полный комплект классов и артефактов Spark в файл uberJAR, то его размер станет действительно огромным, а кроме того, возможно возникновение конфликтов между библиотеками. Поскольку в комплект Spark входит более 220 библиотек, нет необходимости включать в файл uberJAR зависимости, которые уже доступны в целевой системе. Такие зависимости можно определить как исключения по имени соответствующего пакета, например для исключения Hadoop: org.apache.hadoop
Или для артефактов с помощью шаблонных символов, как в показанном ниже случае для библиотеки имитации для тестов: jmock:*
Тесты, несмотря на их чрезвычайную важность, и библиотеки их поддержки не нужны при развертывании. В листинге 6.2 показан пропуск в списке исключений. Файл проекта pom.xml в репозитории Git для главы 5 содержит практически исчерпы-
Глава 6 Развертывание простого приложения
182
вающий список исключений, который можно использовать как основу в ваших проектах. В каталоге проекта (где расположен файл pom.xml) можно создать файл uberJAR, выполнив следующую команду: $ mvn package
Результат находится в целевом каталоге target: $ ls -l target … -rw-r--r-- … 748218 … spark-chapter05-1.0.0-SNAPSHOT-uber.JAR -rw-r--r-- … 25308 … spark-chapter05-1.0.0-SNAPSHOT.JAR
Размер файла uberJAR намного больше (около 750 Кб вместо 25 Кб для обычного JAR-файла), но вы можете попробовать временно удалить исключения и отключить параметр minimizeJAR, чтобы увидеть воздействие этих параметров на размер файла uberJAR.
6.3.2 Создание приложения с использованием Git и Maven При изучении возможных способов развертывания другим предлагаемым вариантом является передача исходного кода и локальная (ре)компиляция. Должен признаться, что я предпочитаю именно этот способ, потому что он позволяет настраивать параметры на сервере и возвращать код в систему управления исходным кодом. Вероятнее всего, эксперты по обеспечению безопасности не позволят вам применить этот вариант в системе, находящейся в реальной эксплуатации (возможно, в наши дни это – правильное ограничение). Но в среде разработки я непреклонно поддерживаю этот вариант. Вы можете обратиться к среде тестирования в зависимости от степени зрелости вашей компании в использовании DevOps. Если вы полностью управляете процессами CICD, то нет почти никакой необходимости в локальной рекомпиляции кода на сервере разработки. Если процесс развертывания все еще содержит множество ручных операций или если конвейер CICD слишком сложен и запутан, то локальная компиляция может помочь. В приложении H предлагается несколько чрезвычайно важных рекомендаций, способных упростить практическое использование Maven. ДОСТ УП К СЕРВЕРУ СИСТЕМЫ УПРАВЛЕНИЯ ИСХОДНЫМ КОДОМ Развертывание кода на целевой системе требует обеспечения доступа этой целевой системы к репозиторию с исходным кодом. В некоторых случаях доступ может оказаться нестандартным и затрудненным. Я работал над проектом, в котором пользователи идентифицировались через механизм Active Directory/LDAP для входа в систему управления исходным кодом, поэтому пользователям нельзя было оставлять свои регистрационные имена и пароли в открытом доступе на сервере разработки. К счастью, такие программные продукты, как Bitbucket, поддерживают использование открытых и секретных ключей.
Создание приложения для работы в кластере
183
В рассматриваемом здесь примере исходный код доступен без ограничений на сайте GitHub, поэтому вы можете легко получить его и разместить на узле, на котором предполагается выполнять приложение как программу-драйвер. В рассматриваемом здесь примере таким узлом является un. Нет необходимости запускать приложение на каждом узле. Введите следующую команду: $ git clone https://github.com/jgperrin/net.jgp.books.spark.ch05.git remote: Counting objects: 296, done. remote: Compressing objects: 100% (125/125), done. remote: Total 296 (delta 72), reused 261 (delta 37), pack-reused 0 Receiving objects: 100% (296/296), 38.04 KiB | 998.00 KiB/s, done. Resolving deltas: 100% (72/72), done. $ cd net.jgp.books.spark.ch05
Теперь можно скомпилировать и установить все требуемые артефакты, просто выполнив команду mvn install. Следует отметить, что при первом выполнении этой команды процесс компиляции и установки может занять немного больше времени, так как Maven загружает все необходимые зависимости: $ mvn install [INFO] Scanning for projects... [INFO] [INFO] -------------------------------------------------------------------[INFO] Building spark-chapter05 1.0.0-SNAPSHOT [INFO] -------------------------------------------------------------------Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/ ➥ maven-resources-plugin/2.6/maven-resources-plugin-2.6.pom … Downloaded from central: https://repo.maven.apache.org/maven2/org/codehaus/plexus/ ➥ plexus-utils/3.0.5/plexus-utils-3.0.5.JAR (230 kB at 2.9 MB/s) [INFO] Installing /home/jgp/net.jgp.books.spark.ch05/target/ ➥ spark-chapter05-1.0.0-SNAPSHOT.JAR to ➥ /home/jgp/.m2/repository/net/jgp/books/spark-chapter05/ ➥ 1.0.0-SNAPSHOT/spark-chapter05-1.0.0-SNAPSHOT.JAR [INFO] Installing /home/jgp/net.jgp.books.spark.ch05/pom.xml to ➥ /home/jgp/.m2/repository/net/jgp/books/spark-chapter05/ ➥ 1.0.0-SNAPSHOT/spark-chapter05-1.0.0-SNAPSHOT.pom [INFO] Installing /home/jgp/net.jgp.books.spark.ch05/target/ ➥ spark-chapter05-1.0.0-SNAPSHOT-sources.JAR to ➥ /home/jgp/.m2/repository/net/jgp/books/spark-chapter05/ ➥ 1.0.0-SNAPSHOT/spark-chapter05-1.0.0-SNAPSHOT-sources.JAR [INFO] -------------------------------------------------------------------[INFO] BUILD SUCCESS [INFO] -------------------------------------------------------------------[INFO] Total time: 52.643 s [INFO] Finished at: 2018-08-19T14:39:29-04:00 [INFO] Final Memory: 50M/1234M [INFO] -------------------------------------------------------------------❶ Сборка и установка архивного файла JAR приложения. ❷ Сборка и установка исходного кода приложения.
❶
❷
184
Глава 6 Развертывание простого приложения
Следует отметить, что пакет, содержащий исходный код приложения, также был создан и установлен. В рассматриваемом здесь примере я использовал свою личную учетную запись на узле un, но вы можете воспользоваться общей учетной записью или обеспечить совместное использование этого репозитория Maven всеми пользователями. Далее можно проверить содержимое локального репозитория Maven: $ ls -1 ~/.m2/repository/net/jgp/books/spark-chapter05/1.0.0-SNAPSHOT/ … spark-chapter05-1.0.0-SNAPSHOT-sources.JAR spark-chapter05-1.0.0-SNAPSHOT-uber.JAR spark-chapter05-1.0.0-SNAPSHOT.JAR spark-chapter05-1.0.0-SNAPSHOT.pom
Действительно ли развертывается исходный код Слышу возмущенные голоса: «Вы в своем уме? Почему вы открыто развертываете исходный код, нашу самую ценную собственность?» Можно было бы возразить, что самую главную ценность, вероятнее всего, представляет не исходный код, а ваши данные. Но это не относится к теме текущей главы. На протяжении почти всей профессиональной деятельности я использовал программное обеспечение для управления исходным кодом: Concurrent Versions System (CVS), Apache Subversion (SVN), Git и даже Microsoft Visual SourceSafe. Но по аналогии с цепью, состоящей из отдельных звеньев, любой процесс настолько прочен и надежен, насколько надежен самый слабый из его элементов. Самый слабый элемент обычно находится между клавиатурой и креслом – это человек. Бесчисленное количество раз, несмотря на все процессы, правила и автоматизацию, я и моя группа не могли восстановить исходный код, который полностью соответствовал бы развертываемой версии: то не был установлен нужный тег, то требуемая ветвь не была создана, то архив не был скомпонован… По известному закону Мерфи вы всегда сталкиваетесь с проблемами в реальной эксплуатации именно того приложения, исходный код которого был безвозвратно утерян. Ну ладно, это слишком вольная интерпретация закона Мерфи, но суть вы поняли. Поэтому всем, кто задавал вопросы, приведенные в начале этого примечания, я отвечаю: «Ну и что». Потому что в процессе восстановления работоспособности вышедшей из строя реальной производственной системы приоритетом является уверенность в том, что конкретная группа получает доступ к необходимой в данный момент собственности (имуществу, активам и т. п.), а развертывание соответствующего исходного кода в известной степени обеспечивает такой доступ. Maven способен обеспечить уверенность в том, что для развернутого для эксплуатации приложения имеется соответствующий исходный код, как показано в листинге 6.3.
Можно без затруднений приказать Maven автоматически создавать пакет, содержащий исходный код приложения.
185
Выполнение приложения в кластере
Листинг 6.3 Обеспечение развертывания Maven исходного кода вместе с приложением
…
org.apache.maven.plugins maven-source-plugin 3.0.1
attach-sources verify
jar-no-fork
⎫ ⎬ ⎭
❶
❷
❶ Определение подключаемого модуля. ❷ Во время создания пакета запрещено создание ветвей исходного кода.
После создания JAR-файла можно выполнить его в кластере.
6.4
Выполнение приложения в кластере Итак, мы пришли к завершающему этапу. После изучения всех главных концепций, на основе которых работает Spark, способов взаимодействия со Spark, создания всех необходимых JAR-файлов и получения более подробной информации о работе с Maven можно, наконец, выполнить приложение в кластере. И это не шутка. В разделе 6.3 были созданы два артефакта, которые можно выполнить: 1 2
файл uberJAR, который будет передан в Spark; файл JAR из скомпилированного исходного кода.
Теперь мы развернем и выполним эти два артефакта. Выбор варианта для выполнения зависит от того, как выполнена сборка приложения.
6.4.1 Передача файла uberJAR Первый вариант – выполнение файла uberJAR, собранного с помощью spark-submit. Это файл uberJAR, подготовленный в разделе 6.3.1. Необходим только этот JAR-файл и ничего больше. Выгрузка файла uberJAR на сервер выполняется командой: $ cd /opt/apache-spark/bin
186
Глава 6 Развертывание простого приложения
Затем выполняется передача приложения на ведущий узел: $ ./spark-submit \ --class net.jgp.books. spark.ch05.lab210. ➥ piComputeClusterSubmitJob.PiComputeClusterSubmitJobApp \ --master "spark://un:7077" \ /spark-chapter05-1.0.0-SNAPSHOT.JAR
Spark выводит подробную информацию, но через журнал, однако вы сможете увидеть следующие сообщения: … About to throw 100000 darts, ready? Stay away from the target! … 2018-08-20 11:52:14 INFO SparkContext:54 - Added JAR file:/home/jgp/.m2/repository/net/jgp/books/spark-chapter05/ ➥ 1.0.0-SNAPSHOT/spark-chapter05-1.0.0-SNAPSHOT.JAR at spark://un.oplo.io:42805/JARs/spark-chapter05-1.0.0-SNAPSHOT.JAR ➥ with timestamp 1534780334746 … 2018-08-20 11:52:14 INFO StandaloneAppClient$ClientEndpoint:54 - Executor ➥ added: app-20180820115214-0006/2 on ➥ worker-20180819144804-10.0.100.83-44763 (10.0.100.83:44763) ➥ with 4 core(s) … Initial dataframe built in 3005 ms Throwing darts done in 49 ms … Analyzing result in 2248 ms Pi is roughly 3.14448 …
❶
❷
❶ Spark делает этот JAR-файл доступным для загрузки всеми рабочими узлами. ❷ Успешно завершено создание исполнителя.
6.4.2 Выполнение приложения
Второй вариант выполнения приложения – запуск его непосредственно через Maven. Это продолжение процедуры локальной компиляции, описанной в разделе 6.3.2. Сначала необходимо перейти в каталог, где находится исходный код приложения: $ cd ~/net.jgp.books.spark.ch05
Затем выполняется следующая команда: $ mvn clean install exec:exec [INFO] Scanning for projects... … [INFO] --- exec-maven-plugin:1.6.0:exec (default-cli) @ spark-chapter05 --About to throw 100000 darts, ready? Stay away from the target! Session initialized in 1744 ms Initial dataframe built in 3078 ms
❶
Выполнение приложения в кластере
187
Throwing darts done in 23 ms Analyzing result in 2438 ms Pi is roughly 3.14124 … [INFO] BUILD SUCCESS … ❶ Maven выполняет очистку, рекомпиляцию, затем выполнение кода приложения.
Приложение было успешно выполнено двумя способами. Рассмотрим подробнее, что происходит внутри.
6.4.3 Анализ пользовательского интерфейса Spark В разделе 6.2 при создании кластера вы узнали, что у Spark есть пользовательский интерфейс, к которому можно получить доступ через порт 8080 (по умолчанию) на ведущем узле. Теперь, после запусков первых приложений, вы можете вернуться к этим визуальным представлениям, которые показывают состояние кластера и приложений – как работающих, так и завершенных. Необходимо перейти к веб-интерфейсу ведущего узла (в рассматриваемом здесь примере это адрес http://un:8080). На рис. 6.7 показан вид интерфейса после выполнения нескольких тестов. Информация о кластере
Имеется одно выполняющееся приложение
Предыдущие (завершенные) приложения и их состояния
Рис. 6.7 Пользовательский интерфейс Spark, в котором показано выполняющееся приложение, а также состояние кластера
После обновления экрана приложение будет перемещено в раздел Completed Applications (Завершенные приложения). Если щелкнуть по
Глава 6 Развертывание простого приложения
188
этой ссылке, то вы получите доступ к подробной информации о его выполнении, включая стандартный поток вывода и стандартный поток ошибок. Если посмотреть содержимое файла журнала, как показано на рис. 6.8, то можно обнаружить более подробную информацию о выполнении этого приложения. Здесь можно видеть, что соединение с ведущим узлом было успешно установлено, а исполнитель начинает работу. Это четвертый узел: quatre или 10.0.100.84
Соединение с ведущим узлом успешно установлено
Исполнитель приступает к работе
Рис. 6.8 Анализ журнала рабочего узла позволяет получить точную отладочную информацию
Резюме Spark поддерживает три режима выполнения: локальный режим, режим кластера и интерактивный режим. Локальный режим позволяет разработчикам начать разработку для Spark буквально за несколько минут. Режим кластера используется для производственной эксплуатации. Можно передать задание в Spark или установить соединение с ведущим узлом. Приложение, оно же программа-драйвер, находится там, где расположен метод main(). Ведущий узел знает обо всех рабочих узлах. Процесс выполнения осуществляется на рабочих узлах. В режиме кластера Spark выполняет процедуру распределения JARфайла приложения на каждый рабочий узел.
Резюме
189
CICD (непрерывная интеграция и непрерывная доставка) – это гибкая методология, которая стимулирует регулярную и часто выполняемую интеграцию и доставку. Spark предоставляет веб-интерфейс для анализа выполнения заданий и приложений. Я начинал свою профессиональную карьеру как разработчик на VB3.
Часть II Потребление данных П
отребление (ingestion) – это слегка причудливое название операции размещения данных в конкретной системе. Я согласен с вами: это слово звучит слишком похоже на «пищеварение» (digestion) и, возможно, на первый взгляд выглядит несколько непривычно (и даже устрашающе). Как бы то ни было, пусть вас не смущает слишком малый размер этой части – всего четыре главы. Эти главы чрезвычайно важны, для того чтобы приступить к практической работе с большими данными. В этих главах рассматривается, как Spark «переваривает» данные, превращая файлы в потоки. На рисунке (б/н), приведенном ниже, показаны основные темы глав этого раздела. Обычные форматы файлов, например, CSV, текстовый, JSON, XML, а также форматы больших данных, такие как Avro, ORC, Parquet (и многие другие)
Потребление данных в фреймы данных
Обработка данных: повышение качества данных, преобразования и многое другое…
Цель (цели) и результаты
Источники
Общий процесс потребления данных, описываемый в следующих четырех главах, начиная с потребления данных из файлов, затем из баз данных, систем и потоков
Потребление данных
191
В главе 7 внимание сосредоточено на потреблении данных из файлов. Типы файлов могут быть не только широко известными, например CSV, текстовые, JSON, XML, но также представлять собой новое поколение форматов файлов, созданных для больших данных. Вы узнаете, почему были созданы такие форматы, а кроме того, будут подробно описаны такие форматы, как Avro, ORC и Parquet. Для каждого формата файла рассматривается отдельный пример. В главе 8 описывается потребление из баз данных независимо от того, поддерживается ли какая-либо конкретная база данных Spark или нет. В этой главе также показано, как выполняется потребление данных из Elasticsearch. Для наглядного представления процессов потребления используется множество примеров. Глава 9 повествует о потреблении данных из разнообразных источников. Данные не всегда хранятся в файлах и базах данных, не так ли? В главе 9 рассматриваются способы, подходящие для поиска источников данных и для создания собственных источников данных. Пример в этой главе демонстрирует, как организовать потребление данных, содержащихся в коллекции цифровых фотографий. В главе 10 рассматривается работа с потоковыми данными. После краткого описания сущности потоковых данных вы будете выполнять операцию потребления данных из одного потока – нет, давайте действовать смелее, – из двух потоков. В этом примере используется генератор потоковых данных, доступный исключительно вам.
7
Потребление данных из файлов
Краткое содержание главы:
общие принципы поведения парсеров (анализаторов синтаксиса); потребление данных из файлов форматов CSV, JSON, XML и из текстовых файлов; объяснение различий между однострочными и многострочными записями JSON; объяснение необходимости специализированных форматов файлов для больших данных.
Потребление (ingestion) – это первый этап в конвейере обработки больших данных. Данные будут находиться в конкретном экземпляре Spark независимо от того, работаете вы в локальном режиме или в режиме кластера. Теперь вам уже известно, что данные в Spark нерезидентны (непостоянны), т. е. после завершения работы в Spark данные не сохраняются. Вы узнаете, как импортировать данные из файлов стандартных форматов, в том числе CSV, JSON, XML и из текстовых файлов. В этой главе после изучения общего поведения различных парсеров (анализаторов синтаксиса) будут использоваться специально подготовленные наборы данных для демонстрации конкретных вариантов, а также наборы данных, взятые с платформ общедоступных данных. Возникает искушающая мысль о том, чтобы сразу начать выполнение анализа этих наборов данных. Когда вы видите данные, выведенные на экран, то начинаете думать: «А что произойдет, если я соединю этот набор данных с другим имеющимся у меня набором? Что, если я начну операцию агрегирования по этому полю?...» Вы научитесь выполнять эти операции в главах с 11 по 15, а также в главе 17, но сначала необходимо поместить все эти данные в Spark.
Потребление данных из файлов
193
Примеры в этой главе выполнены на основе Spark v3.0. Со временем поведение изменяется, особенно при обработке файлов формата CSV. Приложение L дополняет эту главу в качестве справочника по возможностям и параметрам операции потребления данных. После того как вы научитесь потреблять данные из файлов в этой главе, можно будет использовать приложение L как справочное руководство, чтобы при разработке всегда иметь под рукой информацию по всем форматам и параметрам в одном удобно организованном месте. Для каждого формата, рассматриваемого в этой главе, вы найдете информацию, организованную в следующем порядке: описание файла, данные из которого необходимо потреблять; требуемый вывод, демонстрирующий результат работы конкретного приложения; подробное пошаговое описание этого приложения, чтобы вы точно знали, как использовать и настраивать конкретный парсер (анализатор синтаксиса). Для больших данных широко используются новые форматы файлов, так как CSV или JSON уже не оправдывают ожиданий. Далее в этой главе вы узнаете о новых, широко распространенных форматах (таких как Avro, ORC, Parquet и Copybook). На рис. 7.1 показано ваше текущее местоположение в процессе изучения потребления данных. Обычные форматы файлов, например, CSV, текстовый, JSON, XML, а также форматы больших данных, такие как Avro, ORC, Parquet (и многие другие)
Потребление данных в фреймы данных
Обработка данных: повышение качества данных, преобразования и многое другое…
Цель (цели) и результаты
Источники
Рис. 7.1 Процесс изучения потребления данных из внешних источников: в этой главе внимание сосредоточено на файлах
Глава 7 Потребление данных из файлов
194
ЛАБОРАТОРНАЯ РАБОТА Все примеры из этой главы доступны на сайте GitHub в репозитории https://github.com/jgperrin/net.jgp. books.spark.ch07. В приложении L содержится справочное руководство по потреблению данных.
7.1
Общее поведение парсеров Парсеры (parsers), или анализаторы синтаксиса, – это инструментальные средства, которые позволяют передавать данные из неструктурированного источника, такого как файл, во внутреннюю структуру, которой в Spark является фрейм данных. Все парсеры, которые будут использоваться в этой главе, обладают похожими свойствами поведения: для парсера потоком ввода является файл, который можно разместить в требуемой путевой локации. При считывании файлов в путевом имени можно использовать регулярные выражения (regular expressions – regex), т. е. если, например, задан шаблон a*, то данные будут потребляться из всех файлов, имена которых начинаются на a; имена параметров нечувствительны к регистру букв, т. е. multiline и multiLine – это один и тот же параметр. Эти свойства поведения зависят от конкретной реализации, поэтому при использовании библиотек поддержки потребления от сторонних производителей (см. главу 9), возможно, поведение не будет одинаковым. Для потребления данных из файла с особым (нестандартным) форматом можно создать специализированные источники данных (также описанных в главе 9). Тем не менее при создании собственных компонент приложения необходимо всегда помнить о перечисленных выше общих свойствах поведения.
7.2
Сложная процедура потребления данных из CSV-файла Формат данных с использованием запятой для разделения значений (comma-separated values – CSV), вероятно, представляет собой самый распространенный формат обмена данными, используемый повсеместно1. Этот формат существует уже давно и широко используется, поэтому есть несколько вариантов его основной структуры: разделителями не всегда являются запятые, некоторые записи могут располагаться на нескольких строках, существуют различные способы экранирования (блокирования) символа-разделителя и многие другие условия и особенности форматирования. Поэтому, когда клиент сообщает: «Я сейчас 1
Более подробную информацию можно найти на соответствующей странице «Википедии»: https://en.wikipedia.org/wiki/Comma-separated_values; https:// ru.wikipedia.org/wiki/CSV. В разделе об истории появления и развития этого формата вы узнаете, что CSV существует уже достаточно давно.
Сложная процедура потребления данных из CSV-файла
195
отправлю вам CSV-файл», вы можете кивнуть в знак согласия и начать постепенно выходить из себя. К счастью, Spark предлагает разнообразные возможности для потребления данных из CSV-файлов. Процедура потребления CSV-данных проста, а логический вывод схемы представляет собой мощную функциональную возможность. В главах 1 и 2 вы уже выполняли процедуру потребления данных, но здесь будут рассматриваться более сложные примеры с разнообразными вариантами, демонстрирующие сложность обработки CSV-файлов в реальном мире. Сначала рассматривается сам потребляемый CSV-файл, чтобы понять его внутреннюю структуру и особенности. Затем приводится результат потребления и, наконец, создается небольшое приложение, которое обеспечивает получение этого результата. Этот шаблон будет повторяться для каждого формата. ЛАБОРАТОРНАЯ РАБОТА Это лабораторная работа #200. В этом разделе подробно рассматривается пример net.jgp.books.spark.ch07. lab200_csv_ingestion.ComplexCsvToDataframeApp. На рис. 7.2 показан процесс, который будет реализован при рассмотрении этого примера.
Рис. 7.2 Spark выполняет операцию потребления данных из CSV-файла с параметрами, отличающимися от заданных по умолчанию. После завершения операции потребления из файла данные будут находиться в фрейме данных, из которого можно вывести записи и схему. В рассматриваемом здесь примере Spark логически выводит эту схему
В листинге 7.1 показана небольшая часть CSV-файла с двумя записями и строкой заголовка. Следует отметить, что аббревиатура CSV стала более обобщенным обозначением: в наши дни C значит character (символ) чаще, чем comma (запятая). Вам будут встречаться файлы, в которых значения разделяются точками с запятой, табуляциями, вертикальными черточками (|) и т. д. Для сторонников абсолютной точности терминов толкование аббревиатуры CSV может иметь важное значение, но для Spark все символы-разделители относятся к одной категории.
Глава 7 Потребление данных из файлов
196
Несколько замечаний: рассматриваемый здесь файл содержит значения, разделенные не запятой, а точкой с запятой; я вручную добавил символ конца абзаца (¶), чтобы явно показать конец каждой строки (записи). Этого символа нет в исходном файле; если внимательно посмотреть на запись с идентификатором ID 4, то можно обнаружить точку с запятой в названии книги. Это может нарушить корректность процедуры парсинга, поэтому все поле названия книги окружено символами «звездочка». Следует помнить о том, что этот пример специально усложнен для демонстрации некоторых функциональных возможностей Spark; если внимательно посмотреть на запись с идентификатором ID 6, то можно видеть, что название книги располагается в двух строках: здесь имеется символ перехода на новую строку (символ конца абзаца) после слова Language? и перед словом An.
Листинг 7.1 Сложный CSV-файл (часть файла books.csv) id;authorId;title;releaseDate;link ¶ 4;1;*Harry Potter and the Chamber of Secrets: The Illustrated Edition (Harr ➥ y Potter; Book 2)*;10/04/2016;http://amzn.to/2kYhL5n ¶ 6;2;*Development Tools in 2006: any Room for a 4GL-style Language? ¶ An independent study by Jean Georges Perrin, IIUG Board Member*;12/28/2016; ➥ http://amzn.to/2vBxOe1 ¶
7.2.1 Требуемый вывод результата В листинге 7.2 показан возможный вариант вывода. Я добавил символы конца абзаца, чтобы явно обозначить новые строки, поскольку записи действительно трудно читать. Листинг 7.2 Требуемый вывод результата после потребления данных из сложного CSV-файла Excerpt of the dataframe content: +---+--------+------------------------------------------------------------➥ -----------------------------+-----------+-----------------------+¶ | id|authorId| ➥ title|releaseDate| link|¶ +---+--------+------------------------------------------------------------➥ -----------------------------+-----------+-----------------------+¶ … | 4| 1| Harry Potter and the Chamber of Secrets: The Illustrated E ➥ dition (Harry Potter; Book 2)| 10/14/16|http://amzn.to/2kYhL5n|¶ … | 6| 2|Development Tools in 2006: any Room for a 4GL-style Language? ¶ An independent study by...| 12/28/16|http://amzn.to/2vBxOe1|¶ … +---+--------+------------------------------------------------------------➥ -----------------------------+-----------+-----------------------+¶
❶
197
Сложная процедура потребления данных из CSV-файла only showing top 7 rows Dataframe's schema: root |-- id: integer (nullable = true) |-- authorId: integer (nullable = true) |-- title: string (nullable = true) |-- releaseDate: string (nullable = true) |-- link: string (nullable = true)
⎫ ❷ ⎭ ❸
❶ Этот символ перехода на новую строку, который присутствовал в исходном CSV-файле, остается
на месте.
❷ Тип данных integer (целое число). В CSV-файлах все элементы являются строками, но вы можете
попросить Spark сделать обоснованное предположение.
❸ Обратите внимание: дата выпуска книги выглядит как строка, а не как дата в специальном фор-
мате.
7.2.2 Код Чтобы получить результат, показанный в листинге 7.2, потребуется исходный код, подобный приведенному в листинге 7.3. Сначала создается сеанс, затем выполняется конфигурирование и начинается операция парсинга – в одном вызове с использованием цепочного вызова методов. Наконец, выводятся некоторые записи и схема фрейма данных. Если вы не знакомы со схемами, то можете получить информацию о них в приложении E. Листинг 7.3 Приложение ComplexCsvToDataframeApp.java: потребление и вывод данных из сложного CSV-файла package net.jgp.books.spark.ch07.lab200_csv_ingestion; import org.apache.spark.sql.Dataset; import org.apache.spark.sql.Row; import org.apache.spark.sql.SparkSession; public class ComplexCsvToDataframeApp { public static void main(String[] args) { ComplexCsvToDataframeApp app = new ComplexCsvToDataframeApp(); app.start(); } private void start() { SparkSession spark = SparkSession.builder() .appName("Complex CSV to Dataframe") .master("local") .getOrCreate(); Dataset df = spark.read().format("csv") .option("header", "true") .option("multiline", true) .option("sep", ";") .option("quote", "*") .option("dateFormat", "M/d/y") .option("inferSchema", true) .load("data/books.csv");
❶ ❷ ❸ ❹ ❺ ❻ ❼
Глава 7 Потребление данных из файлов
198
System.out.println("Excerpt of the dataframe content:"); df.show(7, 90); System.out.println("Dataframe's schema:"); df.printSchema(); } } ❶ Формат для потребления данных: CSV. ❷ Первая строка этого CSV-файла – заголовок. ❸ Несколько записей в этом файле размещены на нескольких строках. Можно использовать либо ❹ ❺ ❻ ❼
тип string (строка), либо логическое (Boolean) значение, чтобы упростить загрузку значений параметров из файла конфигурации. Разделителем значений является точка с запятой (;). Символом кавычек является звездочка (*). Формат даты соответствует формату месяц/день/год, используемому повсеместно в США. Spark логически выводит (самостоятельно определяет) схему.
Вероятно, вы уже поняли, что необходимо знать, как выглядит содержимое обрабатываемого файла (символ-разделитель, символ экранирования и т. п.), прежде чем начать конфигурирование парсера. Эти характеристики Spark не может определить сам. Формат является частью соглашения, непосредственно связанного с конкретными CSV-файлами (хотя в большинстве случаев вы не получите точное описание формата, поэтому придется определять его особенности самостоятельно). Функция логического вывода схемы (schema inference) – великолепное функциональное свойство Spark. Но, как вы видели в приведенном выше примере, эта функция не смогла определить, что столбец releaseDate являлся датой. Одним из способов сообщить Spark, что это значение является датой, – явное определение схемы.
7.3
Потребление CSV-данных с известной схемой В предыдущем разделе вы узнали, что потребление CSV-данных выполняется просто, а логический вывод схемы является мощной функциональной возможностью. Но когда известна структура (схема) CSV-файла, может оказаться удобным явно определить типы данных, сообщив Spark рекомендуемую к использованию схему. Логический вывод схемы – дорогостоящая операция, а ее явное определение позволяет более точно управлять типами данных (см. в приложении L список типов данных и дополнительные советы по потреблению данных). ЛАБОРАТОРНАЯ РАБОТА Это лабораторная работа #300. В этом разделе подробно рассматривается пример net.jgp.books.spark.ch07. lab300_csv_ingestion_with_schema.ComplexCsvToDataframeWithSchemaApp. В рассматриваемом здесь примере, как и в предыдущем, сначала создается сеанс, затем определяется схема, после чего выполняется парсинг файла с помощью предлагаемой схемы. На рис. 7.3 показан этот процесс.
Потребление CSV-данных с известной схемой
199
Рис. 7.3 Spark выполняет операцию потребления данных из сложного CSV-файла с помощью существующей схемы. В этом случае Spark не должен логически выводить схему. После завершения операции потребления Spark выводит некоторые записи и схему
К сожалению, здесь отсутствует возможность определить, может ли столбец содержать значение null (допустимость нулевых значений). Такой параметр существует, но парсер не принимает его во внимание (в листинге 7.5 показано использование этого параметра). Операция потребления выполняется с тем же файлом, что и в листинге 7.1.
7.3.1 Требуемый вывод результата Требуемый вывод результата похож на показанный в листинге 7.2. Но схема в листинге 7.4 теперь другая, так как была определена собственная схема вместо той, которую мог бы логически вывести Spark. Листинг 7.4 Предварительно определенная схема +---+---------+---------------+-----------+---------------+ | id|authordId| bookTitle|releaseDate| url| +---+---------+---------------+-----------+---------------+ | 1| 1|Fantastic Be...| 2016-11-18|http://amzn....| | 2| 1|Harry Potter...| 2015-10-06|http://amzn....| | 3| 1|The Tales of...| 2008-12-04|http://amzn....| | 4| 1|Harry Potter...| 2016-10-04|http://amzn....| | 5| 2|Informix 12....| 2017-04-23|http://amzn....| +---+---------+---------------+-----------+---------------+ only showing top 5 rows root |-|-|-|-|--
id: integer (nullable = true) authordId: integer (nullable = true) bookTitle: string (nullable = true) releaseDate: date (nullable = true) url: string (nullable = true)
❶ Заголовки столбцов отличаются от существующих в исходном CSV-файле. ❷ Теперь используется настоящий формат даты.
Powered by TCPDF (www.tcpdf.org)
❶
❷
Глава 7 Потребление данных из файлов
200
7.3.2 Код В листинге 7.5 показано, как создать собственную схему, выполнить потребление данных из CSV-файла с использованием заданной схемы и вывести содержимое фрейма данных. Для сохранения небольшого размера примера я удалил некоторые инструкции импортирования (которые аналогичны инструкциям в листинге 7.3) и метод main(), единственной задачей которого является создание сеанса и вызов метода start() (точно так же, как в листинге 7.3 и во многих других примерах в книге). Опущенные блоки кода заменены многоточием (…). Листинг 7.5 Приложение ComplexCsvToDataframeWithSchemaApp.java (код приведен частично) package net.jgp.books.spark.ch07.lab300_csv_ingestion_with_schema; … import org.apache.spark.sql.types.DataTypes; import org.apache.spark.sql.types.StructField; import org.apache.spark.sql.types.StructType; public class ComplexCsvToDataframeWithSchemaApp { … private void start() { SparkSession spark = SparkSession.builder() .appName("Complex CSV with a schema to Dataframe") .master("local") .getOrCreate(); StructType schema = DataTypes.createStructType(new StructField[] { DataTypes.createStructField( "id", DataTypes.IntegerType, false), DataTypes.createStructField( "authordId", DataTypes.IntegerType, true), DataTypes.createStructField( "bookTitle", DataTypes.StringType, false), DataTypes.createStructField( "releaseDate", DataTypes.DateType, true), DataTypes.createStructField( "url", DataTypes.StringType, false) }); Dataset df = spark.read().format("csv") .option("header", "true")
❶
❷ ❸ ❹ ❺
❺
Потребление данных из JSON-файла .option("multiline", true) .option("sep", ";") .option("dateFormat", "MM/dd/yyyy") .option("quote", "*") .schema(schema) .load("data/books.csv");
201
❻
df.show(5, 15); df.printSchema(); } } ❶ Это один из способов создания схемы. В этом примере схема – это массив значений типа Struct-
Field.
❷ Имя поля – заменяет имена столбцов в исходном файле. ❸ Определение типа данных. См. в листинге 7.3 список значений с описаниями. ❹ Допустимы ли в этом поле нулевые значения? Равнозначно: может ли это поле принимать зна-
чение null?
❺ Это значение игнорируется парсером. ❻ Сообщает механизму считывания (reader) о необходимости использовать заданную схему.
Если разобрать инструкцию с цепочным вызовом методов на составляющие элементы, то можно увидеть, что метод read() возвращает экземпляр DataFrameReader. Это объект, который вы конфигурируете с использованием методов option(), метода schema() и завершающего метода load(). Как уже было отмечено ранее, для формата CSV существует впечатляющее множество вариантов, но и в Spark имеется не менее впечатляющее количество вариантов, которое постоянно увеличивается. В приложении L перечислены соответствующие параметры.
7.4
Потребление данных из JSON-файла За последние годы JavaScript Object Notation (JSON) стал новым безусловным лидером в области обмена данными, особенно после того, как технология REST (representational state transfer) вытеснила SOAP (Simple Object Access Protocol) и WSDL (Web Services Description Language, написанный на XML) в архитектуре, ориентированной на веб-сервисы. Формат JSON проще читать, он менее избыточен и менее ограничен, чем язык XML. JSON поддерживает вложенные конструкции, такие как массивы и объекты. Более подробно о формате JSON можно узнать на сайте https://www.json.org/. И все же формат JSON остается весьма избыточным. Производный от JSON формат называется JSON Lines (http://jsonlines. org), в котором запись хранится в одной строке, упрощая парсинг и улучшая удобство чтения. Ниже приведен небольшой пример, скопированный с веб-сайта JSON Lines. Здесь можно видеть, что в этом формате поддерживается Unicode: {"name": "Gilbert", "wins": [["straight", "7♣"], ["one pair", "10♥"]]} {"name": "Alexa", "wins": [["two pair", "4♠"], ["two pair", "9♠"]]}
202
Глава 7 Потребление данных из файлов {"name": "May", "wins": []} {"name": "Deloise", "wins": [["three of a kind", "5♣"]]}
До выпуска версии Spark v2.2.0 JSON Lines был единственным форматом JSON, который мог прочитать Spark. На рис. 7.4 показан процесс потребления данных в формате JSON.
Рис. 7.4 Spark выполняет процедуру потребления данных из файла JSON Lines. Записи хранятся в формате JSON, но каждая запись размещена в одной отдельной строке. После завершения процедуры потребления Spark выводит некоторые записи и схему
Для первой операции потребления данных в формате JSON будет использоваться набор данных foreclosure, взятый из города Дурхем (Durham, Северная Каролина) за период с 2006 по 2016 годы. Этот набор данных можно бесплатно загрузить с недавно измененного портала города: https://live-durhamnc.opendata.arcgis.com/. ЛАБОРАТОРНАЯ РАБОТА Это лабораторная работа #400. В этом разделе подробно рассматривается пример net.jgp.books.spark. ch07.lab400_json_ingestion.JsonLinesToDataframeApp. Данные взяты с общедоступного портала Open Durham города и округа Дурхем (Северная Каролина). Предназначенные для использования данные взяты с бывшего общедоступного портала данных с использованием решения Opendatasoft, которое предоставляет данные в формате JSON Lines. Как показано на рис. 7.4, каждая запись располагается в одной строке. В листинге 7.6 показан вывод трех записей (первых двух и последней). Листинг 7.6 Набор данных foreclosure: две первых и самая последняя запись [{"datasetid": "foreclosure-2006-2016", "recordid": "629979c85b1cc68c1d4ee8 ➥ cc351050bfe3592c62", "fields": {"parcel_number": "110138", "geocode": [ ➥ 36.0013755, -78.8922549], "address": "217 E CORPORATION ST", "year": "2 ➥ 006"}, "geometry": {"type": "Point", "coordinates": [-78.8922549, 36.00 ➥ 13755]}, "record_timestamp": "2017-03-06T12:41:48-05:00"}, {"datasetid": "foreclosure-2006-2016", "recordid": "e3cce8bbc3c9b804cbd87e2
Потребление данных из JSON-файла
203
➥ 67a6ff121285274e0", "fields": {"parcel_number": "110535", "geocode": [3 ➥ 5.995797, -78.895396], "address": "401 N QUEEN ST", "year": "2006"}, "g ➥ eometry": {"type": "Point", "coordinates": [-78.895396, 35.995797]},
… {"datasetid": "foreclosure-2006-2016", "recordid": "1d57ed470d533985d5a3c3d ➥ fb37c294eaa775ccf", "fields": {"parcel_number": "194912", "geocode": [3 ➥ 5.955832, -78.742107], "address": "2516 COLEY RD", "year": "2016"}, "ge ➥ ometry": {"type": "Point", "coordinates": [-78.742107, 35.955832]}, "re ➥ cord_timestamp": "2017-03-06T12:41:48-05:00"}]
В листинге 7.7 показана отформатированная версия первой записи (с улучшенным выводом через JSONLint (https://jsonlint.com/) и Eclipse), поэтому вы можете видеть структуру: имена полей, массивы и вложенную структуру. Листинг 7.7 Набор данных foreclosure: улучшенное форматирование вывода первой записи [ { "datasetid": "foreclosure-2006-2016", "recordid": "629979c85b1cc68c1d4ee8cc351050bfe3592c62", "fields": { "parcel_number": "110138", "geocode": [ 36.0013755, -78.8922549 ], "address": "217 E CORPORATION ST", "year": "2006" }, "geometry": { "type": "Point", "coordinates": [ -78.8922549, 36.0013755 ] }, "record_timestamp": "2017-03-06T12:41:48-05:00" } … ]
7.4.1 Требуемый вывод результата В листинге 7.8 показан вывод записей из фрейма данных и схемы после завершения операции потребления данных из документа в формате JSON Lines. Листинг 7.8 Вывод записей и схемы набора данных foreclosure +-------------+-------------+-------------+----------------+-------------+ | datasetid| fields| geometry|record_timestamp| recordid| +-------------+-------------+-------------+----------------+-------------+
Глава 7 Потребление данных из файлов
204
|foreclosur...|[217 E COR...|[WrappedAr...| 2017-03-06...|629979c85b...| |foreclosur...|[401 N QUE...|[WrappedAr...| 2017-03-06...|e3cce8bbc3...| |foreclosur...|[403 N QUE...|[WrappedAr...| 2017-03-06...|311559ebfe...| |foreclosur...|[918 GILBE...|[WrappedAr...| 2017-03-06...|7ec0761bd3...| |foreclosur...|[721 LIBER...|[WrappedAr...| 2017-03-06...|c81ae2921f...| +-------------+-------------+-------------+----------------+-------------+ only showing top 5 rows root |-- datasetid: string (nullable = true) |-- fields: struct (nullable = true) | |-- address: string (nullable = true) | |-- geocode: array (nullable = true) | | |-- element: double (containsNull = true) | |-- parcel_number: string (nullable = true) | |-- year: string (nullable = true) |-- geometry: struct (nullable = true) | |-- coordinates: array (nullable = true) | | |-- element: double (containsNull = true) | |-- type: string (nullable = true) |-- record_timestamp: string (nullable = true) |-- recordid: string (nullable = true) |-- year: string (nullable = true)
❶ ❷ ❸
⎫ ❶ ⎭ ⎫ ⎬
⎪
⎭
❸
❶
❶ Для каждого поля, для которого Spark не может точно определить тип данных, используется тип
string (строка).
❷ Поле fields – структура с вложенными полями. ❸ Фрейм данных может содержать массивы.
Когда вы видите фрагмент данных, похожий на приведенный в листинге 7.8, не возникает ли у вас желания сгруппировать записи по годам, чтобы наблюдать процесс развития залоговых потерь, или вывести каждое событие на карту, чтобы узнать, существуют ли области, более подверженные этому явлению, и сравнить данные со средними доходами в этих областях? Это хороший признак – позвольте вашему внутреннему духу ученого-исследователя в области данных вырваться на свободу. Преобразования данных рассматриваются в части III книги.
7.4.2 Код Считывание данных в формате JSON не намного сложнее, чем потребление содержимого CSV-файла. Вы можете сами убедиться в этом, изучая листинг 7.9. Листинг 7.9 Приложение JsonLinesToDataframeApp.java package net.jgp.books.spark.ch07.lab400_json_ingestion; import org.apache.spark.sql.Dataset; import org.apache.spark.sql.Row; import org.apache.spark.sql.SparkSession; public class JsonLinesToDataframeApp {
205
Потребление данных из многострочного JSON-файла public static void main(String[] args) { JsonLinesToDataframeApp app = new JsonLinesToDataframeApp(); app.start(); } private void start() { SparkSession spark = SparkSession.builder() .appName("JSON Lines to Dataframe") .master("local") .getOrCreate(); Dataset df = spark.read().format("json") .load("data/durham-nc-foreclosure-2006-2016.json");
❶
df.show(5, 13); df.printSchema(); } } ❶ Внимание: это единственное изменение, необходимое для того, чтобы выполнить потребление
данных в формате JSON.
7.5
Потребление данных из многострочного JSON-файла Начиная с версии v2.2, Spark приобрел возможность потребления данных из более сложных файлов в формате JSON, т. е. уже не был ограничен только лишь форматом JSON Lines. В этом разделе будет показано, как обрабатывать такие файлы. Для выполнения этой операции потребления JSON будут использоваться данные рекомендаций по поездкам, предоставляемые Бюро консульских дел (Bureau of Consular Affairs) при Государственном департаменте США (US Department of State). ЛАБОРАТОРНАЯ РАБОТА Это лабораторная работа #500. В этом разделе подробно рассматривается пример net.jgp.books.spark. ch07.lab500_json_multiline_ingestion.MultilineJsonToDataframeApp. Бюро консульских дел предоставляет данные на общедоступном портале на основе CKAN. CKAN – это общедоступный портал данных с открытым исходным кодом. Более подробно о CKAN можно узнать на сайте https://ckan.org/. Доступ к порталу Бюро консульских дел можно получить по адресу https://cadatacatalog.state.gov/. Щелкните по ссылке Travel (Поездки), далее по ссылке countrytravelinfo, затем щелкните по кнопке Go to Resource (Перейти к ресурсу), чтобы скачать файл. На рис. 7.5 показан процесс потребления.
206
Глава 7 Потребление данных из файлов
Рис. 7.5 Spark выполняет потребление JSON-файла, в котором записи располагаются на нескольких строках. После завершения операции потребления Spark выводит некоторые записи и схему
В листинге 7.10 показан фрагмент этого файла. Для удобства чтения я сократил слишком длинные описания. Листинг 7.10 Небольшой фрагмент данных рекомендаций по поездкам от Госдепартамента США [ { "tag" : "A1", "geopoliticalarea" : "Bonaire, Sint Eustatius, and Saba (BES) (Dutch Cari ➥ bbean)", "travel_transportation" : "
Road Conditions …", "health" : "
Medical care on the BES islands …", "local_laws_and_special_circumstances" : "
…", "entry_exit_requirements" : "
All U.S. citizens must…", "destination_description" : "
The three islands of Bonaire…", "iso_code" : "", "travel_embassyAndConsulate" : " 1 ➥ AND (rating="G" OR rating="PG")) film_alias
В этом запросе выполняется поиск кинофильмов, в названии которых содержатся слова alien, victory или agent или в описании которых содержится слово action, со стоимостью проката больше 1 долл. Кроме того, задано ограничение по рейтингу – либо G (General audience – для всех
Расширенные запросы и процесс потребления
241
зрителей), либо PG (Parental Guidance suggested – рекомендуется просмотр под контролем родителей). Следует отметить, что, поскольку используется ключевое слово LIKE, регистр букв не учитывается: будут выведены все фильмы, в названиях которых есть слова alien, Alien и ALIEN. Последнее ключевое слово (film_alias) – это просто псевдоним (alias). На рис. 8.4 изображен процесс, соответствующий этому запросу.
Этот запрос SQL не преобразовывается драйвером JDBC: тот же самый запрос SQL покидает рабочую среду Spark и обращается к экземпляру MySQL
Рис. 8.4 Процесс потребления данных из БД MySQL с использованием драйвера JDBC MySQL. В этом примере нас интересуют только те кинофильмы, которые соответствуют условиям запроса SQL – их записи выделены полужирным шрифтом
В листинге 8.5 показан требуемый вывод результата, т. е. записи, выделенные полужирным шрифтом на рис. 8.4.
Глава 8 Потребление из баз данных
242
Листинг 8.5 Требуемый вывод результата запроса с ключевым словом WHERE +-------+--------------+--------------------+------------+-----------+… |film_id| title| description|release_year|language_id|… +-------+--------------+--------------------+------------+-----------+… | 6| AGENT TRUMAN|A Intrepid Panora...| 2005-12-31| 1|… | 13| ALI FOREVER|A Action-Packed D...| 2005-12-31| 1|… … +-------+--------------+--------------------+------------+-----------+… only showing top 5 rows root |-|-|-|-|-|-|-|-|-|-|-|-|--
film_id: integer (nullable = true) title: string (nullable = true) description: string (nullable = true) release_year: date (nullable = true) language_id: integer (nullable = true) original_language_id: integer (nullable = true) rental_duration: integer (nullable = true) rental_rate: decimal(4,2) (nullable = true) length: integer (nullable = true) replacement_cost: decimal(5,2) (nullable = true) rating: string (nullable = true) special_features: string (nullable = true) last_update: timestamp (nullable = true)
The dataframe contains 16 record(s).
В листинге 8.6 показан исходный код, обеспечивающий выполнение процесса потребления через запрос SQL. Листинг 8.6
Приложение MySQLWithWhereClauseToDatasetApp.java
package net.jgp.books.spark.ch08.lab300_advanced_queries; import import import import
java.util.Properties; org.apache.spark.sql.Dataset; org.apache.spark.sql.Row; org.apache.spark.sql.SparkSession;
public class MySQLWithWhereClauseToDatasetApp { public static void main(String[] args) { MySQLWithWhereClauseToDatasetApp app = new MySQLWithWhereClauseToDatasetApp(); app.start(); } private void start() { SparkSession spark = SparkSession.builder() .appName( "MySQL with where clause to Dataframe using a JDBC Connection") .master("local") .getOrCreate(); Properties props = new Properties();
Расширенные запросы и процесс потребления
243
props.put("user", "root"); props.put("password", "Spark1 " + "and (rating=\"G\" or rating=\"PG\")"; Dataset df = spark.read().jdbc( "jdbc:mysql://localhost:3306/sakila", "(" + sqlQuery + ") film_alias", props);
❶ ❷ ❸
df.show(5); df.printSchema(); System.out.println("The dataframe contains " + df .count() + " record(s)."); } } ❶ Запрос SQL может быть сформирован как любая обычная строка или может быть взят из файла
конфигурации, сгенерирован специализированным механизмом и т. д.
❷ Конец запроса SQL. ❸ Требуемый синтаксис соблюдается: весь запрос SQL заключен в круглые скобки, а в конце указан
псевдоним таблицы.
Необходимо всегда помнить о следующих важных вещах: в инструкции select можно использовать вложенные круглые скобки; псевдоним таблицы не должен совпадать с именем таблицы, существующей в используемой БД.
8.3.2 Соединение данных в базе данных Используя похожую методику, можно выполнять соединение (join) данных в БД перед началом операции потребления в Spark. Spark может соединять данные между фреймами данных (более подробно см. главу 12 и приложение М), но из соображений улучшения производительности и оптимизации, возможно, потребуется выполнение запроса к БД на выполнение операции соединения. В этом разделе рассматривается выполнение операции соединения данных на уровне БД и процедура потребления данных из полученного соединения. ЛАБОРАТОРНАЯ РАБОТА Это лабораторная работа #310. Она доступна на сайте GitHub в репозитории текущей главы https:// github.com/jgperrin/net.jgp.books.spark.ch08. Для этой лабораторной работы потребуется БД MySQL или MariaDB. Будет выполнена следующая инструкция SQL:
244
Глава 8 Потребление из баз данных SELECT actor.first_name, actor.last_name, film.title, film.description FROM actor, film_actor, film WHERE actor.actor_id = film_actor.actor_id AND film_actor.film_id = film.film_id
На рис. 8.5 показан процесс выполнения этой операции.
Этот запрос SQL не преобразовывается драйвером JDBC: тот же самый запрос SQL покидает рабочую среду Spark и обращается к экземпляру MySQL
Рис. 8.5 Spark выполняет потребление данных, хранящихся в БД MySQL, после того как сервер БД выполняет операцию соединения данных из трех таблиц
В листинге 8.7 показан результат. Отметим, что фрейм данных содержит больше записей, чем соединяемые таблицы. Листинг 8.7 Вывод результата соединения данных, выполненного на уровне БД, потребленного Spark +----------+---------+--------------------+--------------------+ |first_name|last_name| title| description| +----------+---------+--------------------+--------------------+ | PENELOPE| GUINESS| ACADEMY DINOSAUR|A Epic Drama of a...| | PENELOPE| GUINESS|ANACONDA CONFESSIONS|A Lacklusture Dis...| | PENELOPE| GUINESS| ANGELS LIFE|A Thoughtful Disp...|
Расширенные запросы и процесс потребления
245
| PENELOPE| GUINESS|BULWORTH COMMANDM...|A Amazing Display...| | PENELOPE| GUINESS| CHEAPER CLYDE|A Emotional Chara...| +----------+---------+--------------------+--------------------+ only showing top 5 rows root |-|-|-|--
first_name: string (nullable = true) last_name: string (nullable = true) title: string (nullable = true) description: string (nullable = true)
The dataframe contains 5462 record(s).
В листинге 8.8 показан исходный код. Как и следовало ожидать, он похож на исходный код фильтрации в листинге 8.6. Избыточные строки кода были удалены. Листинг 8.8 Приложение MySQLWithJoinToDatasetApp.java (код приведен частично) package net.jgp.books.spark.ch08_lab310_sql_joins; … public class MySQLWithJoinToDatasetApp { … private void start() { … String sqlQuery = "select actor.first_name, actor.last_name, film.title, " + "film.description " + "from actor, film_actor, film " + "where actor.actor_id = film_actor.actor_id " + "and film_actor.film_id = film.film_id"; Dataset df = spark.read().jdbc( "jdbc:mysql://localhost:3306/sakila", "(" + sqlQuery + ") actor_film_alias", props); …
❶ ❷
} } ❶ Простой запрос SQL выполняет соединение трех таблиц. ❷ Это тот же запрос, что и в листинге 8.6, за исключением псевдонима таблицы.
Если бы в запросе в листинге 8.8 использовалась инструкция SELECT * FROM actor, film_actor…, то Spark запутался бы в столбцах с одинаковыми именами и должен был бы вывести следующее сообщение об ошибке: Duplicate column name 'actor_id'. Spark не создает полностью определенные имена (.) автоматически, поэтому потребуется явно определить имена столбцов и псевдонимов для них. Исходный код для обеспечения этого исключения доступен на сайте GitHub http://mng.bz/ KEOO.
246
Глава 8 Потребление из баз данных
ПРИМЕЧАНИЕ Код инструкций SQL, приведенный здесь, отправляется непосредственно в MySQL. Этот код не интерпретируется в Spark, следовательно, если вы пишете специализированный код Oracle SQL, то он не будет работать с PostgreSQL (хотя должен работать в IBM Db2, так как эта БД понимает синтаксис Oracle).
8.3.3 Выполнение потребления и распределение данных В этом разделе приведен краткий обзор расширенной функциональной возможности Spark: потребление из БД и автоматическое распределение данных по разделам (partitions). На рис. 8.6 показан фрейм данных после завершения операции потребления данных из таблицы film, как показано в листинге 8.9.
Фрейм данных RDD
Раздел #1 с 1000 записей о кинофильмах
Рис. 8.6 Представление фрейма данных после потребления 1000 записей о кинофильмах из таблицы film. Все записи размещены в одном разделе
На рис. 8.7 показаны разделы (partitions) в устойчивом распределенном наборе данных (RDD) внутри фрейма данных после использования процедуры распределения по разделам. Напомню, что устойчивый распределенный набор данных (RDD) – это хранилище данных, являющееся частью фрейма данных (см. главу 3). Процесс потребления с распределением по разделам подробно показан в листинге 8.11.
Рис. 8.7 В этом варианте вы сообщаете Spark о необходимости распределения данных по 10 разделам. Но при этом продолжает использоваться один фрейм данных и один RDD. Физические узлы здесь не показаны, но эту схему можно распределить по нескольким физическим узлам
247
Расширенные запросы и процесс потребления
ЛАБОРАТОРНАЯ РАБОТА Это лабораторная работа #320. Она доступна на сайте GitHub в репозитории текущей главы https:// github.com/jgperrin/net.jgp.books.spark.ch08. Для этой лабораторной работы потребуется БД MySQL или MariaDB. Листинг 8.9 похож на листинг 8.2, но в этом случае выполняется потребление записей о кинофильмах из таблицы film. Листинг 8.9 Приложение MySQLToDatasetWithoutPartitionApp.java package net.jgp.books.spark.ch08.lab320_ingestion_partinioning; … public class MySQLToDatasetWithoutPartitionApp { … private void start() { … Properties props = new Properties(); props.put("user", "root"); props.put("password", "Spark