Вопросы по Spark на собеседовании
Spark спрашивают у дата-инженеров и дата-сайентистов, работающих с большими объёмами. Ключевой вопрос почти всегда про шафл: откуда он берётся, сколько стоит и как его избежать.
Из чего состоит тема
Так тема разложена в тренажёре: движок ведёт прогресс по каждой подтеме отдельно и возвращает те, где вы ошибаетесь.
- Оптимизация Spark15
- DataFrame API для фич14
- Выборка данных под ML14
- Ядро Spark14
- Hadoop и lakehouse12
- Форматы и хранение12
- Ленивость и действия10
- Когда Spark, а когда pandas9
- От данных к модели9
Разборы подтем
Конспект по каждой: что это, как отвечать вслух, на чём валятся, плюс вопросы для самопроверки.
- Форматы файлов и хранение данных12 вопросов
- Hadoop и lakehouse12 вопросов
- Ядро Spark: RDD и план выполнения14 вопросов
- Оптимизация джобов Spark15 вопросов
- Выборка данных под ML14 вопросов
- DataFrame API для фич14 вопросов
- Spark: ленивость и действия10 вопросов
- Spark: от данных к модели9 вопросов
- Когда Spark, а когда pandas9 вопросов
Примеры вопросов с разбором
- Чем колоночный формат (Parquet) выгоднее строкового (CSV) для аналитики?A)Обычный текстовый CSV читается заметно быстрее Parquet при аналитике по нескольким колонкамB)Parquet и CSV — близкие форматы, отличаются лишь расширением файлаC)Строковый формат позволяет читать одну колонку, не трогая остальные данныеD)Parquet колоночный: читает нужные колонки и жмёт лучше, чем CSV
показать ответ и разбор
+D)Parquet колоночный: читает нужные колонки и жмёт лучше, чем CSV// разбор: Parquet хранит данные по колонкам: запрос читает только нужные столбцы, а не всю строку, и жмёт каждую колонку эффективнее (однотипные значения рядом). Плюс он несёт схему и статистику для предикат-пушдауна. CSV строковый — читать одну колонку без остальных нельзя, сжатие хуже, схемы нет.
- Что такое HDFS и как он хранит большой файл?A)HDFS хранит файл целиком на одном узле, копируя его на соседний как резервную копиюB)HDFS — это реляционная СУБД, хранящая данные строками в таблицах с поддержкой SQL-запросовC)Распределённая ФС: файл режется на крупные блоки, разложенные по DataNode-узлам кластера, — так хранят объёмы больше одного дискаD)HDFS оптимизирован под частые мелкие случайные обновления отдельных байтов внутри файлов
показать ответ и разбор
+C)Распределённая ФС: файл режется на крупные блоки, разложенные по DataNode-узлам кластера, — так хранят объёмы больше одного диска// разбор: HDFS (Hadoop Distributed File System) хранит файлы, которые не влезают на один сервер: файл делится на крупные блоки (обычно 128 МБ), и блоки распределяются по множеству узлов-DataNode. Метаданные (какой файл из каких блоков и где они лежат) держит NameNode. Так достигается и объём (суммарная ёмкость кластера), и параллелизм чтения (разные блоки читаются с разных узлов одновременно), и отказоустойчивость (каждый блок реплицирован). HDFS оптимизирован под большие последовательные чтения/записи, а не под мелкие случайные правки.
- Что такое RDD/DataFrame в Spark на концептуальном уровне?A)Распределённая коллекция данных, разбитая на партиции по узлам кластераB)Одна таблица, целиком помещающаяся в память одного драйвераC)Формат сжатия файлов на диске для колоночного храненияD)Специальный планировщик задач, распределяющий всю работу по воркерам кластера
показать ответ и разбор
+A)Распределённая коллекция данных, разбитая на партиции по узлам кластера// разбор: DataFrame/RDD — абстракция распределённого набора данных: он разбит на партиции, лежащие на разных узлах, и обрабатывается параллельно. Именно поэтому Spark тянет данные больше памяти одной машины. DataFrame поверх RDD добавляет схему и оптимизатор Catalyst, поэтому его предпочитают низкоуровневому RDD.
- Что такое партиция в Spark?A)Логический кусок данных — единица параллелизма, считается одной задачейB)Отдельный физический сервер или узел в распределённом вычислительном кластере SparkC)Копия всего датасета, продублированная для отказоустойчивости системыD)Индекс, ускоряющий точечный поиск строки по ключу в датасете
показать ответ и разбор
+A)Логический кусок данных — единица параллелизма, считается одной задачей// разбор: Партиция — логический фрагмент данных, обрабатываемый одной задачей на одном ядре; число партиций задаёт степень параллелизма. Слишком мало — кластер недозагружен и задачи огромны; слишком много — накладные расходы на планирование задач съедают выигрыш. Тюнинг числа партиций — базовый рычаг производительности.
- Таблица событий партиционирована по дате и хранит 3 года. Тебе нужен один месяц. Как читать, чтобы Spark не поднимал все 3 года?A)Наложить фильтр по колонке-партиции (дате) прямо при чтении — сработает partition pruning, и лишние партиции не прочитаютсяB)Прочитать всё в DataFrame, а потом отфильтровать нужный месяц — Spark всё равно сам выкинет лишнее, и в объёме чтения не будет никакой разницыC)Считать все 3 года сразу в pandas и там взять срез по нужному месяцу привычным способомD)Никак: Spark читает таблицу целиком, партиции на объём чтения не влияют
показать ответ и разбор
+A)Наложить фильтр по колонке-партиции (дате) прямо при чтении — сработает partition pruning, и лишние партиции не прочитаются// разбор: Фильтр по колонке партиционирования во время чтения включает partition pruning — Spark физически пропускает каталоги/файлы других дат. Фильтр «после чтения» помогает меньше: часть данных уже прочитана с диска. Читай сразу с условием по партиции.
- Нужно добавить в DataFrame новую фичу как выражение от существующих колонок. Чем это делают в Spark?A)df.withColumn(имя, выражение) возвращает новый DataFrame с добавленной колонкойB)Прямым присваиванием df["имя"] =..., как в pandas, — оно меняет df на местеC)Только через сырой SQL, из DataFrame API колонки не добавитьD)Через collect(), правку получившегося списка в Python и обратную сборку в DataFrame из строк
показать ответ и разбор
+A)df.withColumn(имя, выражение) возвращает новый DataFrame с добавленной колонкой// разбор: В Spark DataFrame неизменяем: withColumn(имя, выражение) не меняет исходный, а возвращает новый DataFrame с добавленной или переопределённой колонкой. Выражение строят из функций pyspark.sql.functions (col, when, арифметика) — оно ленивое и войдёт в общий план. Присваивание df["x"]=... в стиле pandas тут не работает: объект неизменяем, а операции возвращают новые DataFrame.
- Ты написал цепочку filter().select().join(), запустил ячейку — она вернулась мгновенно. Значит, данные уже обработаны?A)Да: раз ячейка отработала без единой ошибки, Spark уже материализовал результат, и дальнейшее обращение к нему будет мгновеннымB)Нет: это ленивые трансформации, они лишь строят план; работа запустится только на действии (count/collect/write)C)Да, но только потому, что в цепочке был join — именно он заставляет Spark посчитать всё сразуD)Нет: цепочка вообще не сохранилась, её нужно переписать одной строкой без точек
показать ответ и разбор
+B)Нет: это ленивые трансформации, они лишь строят план; работа запустится только на действии (count/collect/write)// разбор: Трансформации (filter/select/join) ленивые — Spark лишь достраивает план вычислений. Реальное чтение и счёт запускаются только на действии: count, collect, show, write. Мгновенный возврат ячейки ≠ данные посчитаны.
- MLlib-модель ждёт на входе один столбец-вектор признаков, а у тебя признаки в разных колонках. Чем их собрать?A)VectorAssembler собирает перечисленные колонки в один столбец-вектор features для MLlibB)Обычным concat строк по колонкамC)GroupBy по всем колонкам сразуD)MLlib-оценщики принимают исходные отдельные колонки, поэтому собирать их во что-то не требуется
показать ответ и разбор
+A)VectorAssembler собирает перечисленные колонки в один столбец-вектор features для MLlib// разбор: Оценщики Spark ML (LogisticRegression, RandomForest и т.д.) работают с одним векторным столбцом признаков. VectorAssembler(inputCols=[...], outputCol="features") склеивает числовые/индексированные колонки в единый вектор. Обычно это последний трансформер в Pipeline перед моделью. Категориальные колонки перед этим переводят в числа (StringIndexer/OneHotEncoder), иначе в вектор их не собрать.
- Датасет 200 МБ спокойно влезает в память ноутбука. Коллега советует «бери Spark, он же для данных». Что разумнее?A)Остаться на pandas: на данных, влезающих в RAM, оверхед планировщика и координации кластера Spark только замедлит работуB)Обязательно взять Spark: pandas не годится для серьёзной аналитики и уже на сотнях мегабайт начинает терять точность вычисленийC)Взять Spark про запас — данные же вырастут, а переписывать пайплайн потом дороже, чем заложить кластер сразуD)Без разницы: на объёме данных оба инструмента дают примерно одинаковую скорость
показать ответ и разбор
+A)Остаться на pandas: на данных, влезающих в RAM, оверхед планировщика и координации кластера Spark только замедлит работу// разбор: Spark окупается, когда данные не влезают в память одной машины или уже лежат распределённо. На 200 МБ pandas проще, быстрее и без накладных расходов на кластер. «Про запас» — преждевременное усложнение: заведёшь Spark, когда реально упрёшься в память.
это 9 из 109
Ещё 100 вопросов по теме — в тренажёре, с движком повторения
Прочитать разбор и ответить самому — разные навыки. В Сеньорчике вопросы идут сессиями, а движок возвращает подтемы, где вы ошибаетесь, пока они не начнут отскакивать. Бесплатно, лимит по энергии.
Частые вопросы
Что такое шафл и почему он дорогой?
Это перераспределение данных между узлами при группировках и джойнах: данные пишутся на диск и едут по сети. Отсюда советы про широковещательные джойны и правильный ключ партиционирования.
Спрашивают ли RDD, если все пишут на DataFrame?
Спрашивают модель: что такое ленивые преобразования и действия, зачем нужен план выполнения. Это помогает объяснить, почему одинаковый по виду код работает по-разному.