deшка
Урок 7.7

Форматы файлов в Data Lake: от JSON до Parquet

Что находится внутри Parquet и как запрос избегает чтения лишних файлов, групп строк и колонок.

Файловые форматы решают разные задачи. Текстовый файл удобно получить от внешней системы и проверить глазами. Большую таблицу, из которой постоянно читают две-три колонки, выгоднее хранить в формате, позволяющем не открывать остальные поля. В Data Lake один и тот же набор может существовать в исходном и подготовленном виде.

{"sensor_id":"s1","observed_at":"2026-09-01T09:14:00Z","temperature_c":21.4}

JSON Lines хранит по одному JSON-сообщению в строке. Его просто дописывать, смотреть глазами и принимать с меняющимся набором полей. Цена — объём повторяющихся имён, разбор текста при каждом чтении и неоднозначность типов, если источник прислал число строкой. JSON Lines удобен в raw, но повторный анализ большого архива бывает дорогим. Обычный JSON может быть и одним большим массивом; для потоковых поставок граница записей в JSON Lines часто удобнее.

Строковые и колоночные форматы

В строковом представлении значения одной записи находятся рядом. Чтобы обработать событие полностью — например, проверить координаты вместе с кодом ошибки, — это естественно. В колоночном представлении значения battery_pct множества событий лежат рядом; запрос, которому нужен только заряд, может не читать фотографию, длинное описание и другие поля. Parquet и ORC — колоночные файловые форматы; они хранят метаданные и блоки значений так, чтобы движок мог выбирать колонки и иногда пропускать группы строк по статистике. Возможность пропуска зависит от записанных метаданных, фильтра и реализации читателя, а не гарантируется одним расширением файла.

Parquet устроен подробнее, чем просто «колонки вместо строк». Файл делится на row groups — группы строк. В каждой группе есть column chunk — отдельный фрагмент для каждой колонки; внутри фрагмента значения записаны pages, страницами. На схеме две группы строк; для каждой показаны отдельные значения id и battery.

Две группы строк Parquet, фрагменты колонок и footer с метаданными

УровеньЧто содержитДля чего полезен
ФайлГруппы строк и метаданные в концеУзнать схему, расположение групп и доступную статистику
Группа строк — row groupОдин диапазон записейПропустить группу целиком, если фильтр не может найти в ней совпадений
Фрагмент колонки — column chunkЗначения одной колонки в одной группеПрочитать battery_pct, не загружая другие колонки этой группы
Страница — pageПорцию значений внутри фрагментаСжимать и декодировать данные порциями; иногда пропускать их по дополнительному индексу

В конце файла находится footer: схема, число строк, адреса фрагментов колонок, размеры и доступная статистика. Читатель получает эти метаданные и решает, какие части файла нужны запросу. Статистика min/max относится к фрагменту колонки в группе строк, а не к каждой строке отдельно. Индекс страниц может дать более тонкий пропуск, но он необязателен и поддерживается не всеми файлами и движками.

ORC решает схожие аналитические задачи, но устроен иначе. Файл ORC делится на stripes — крупные полосы записей. Внутри полосы значения колонок хранятся отдельными потоками; есть индексы и статистика, а в конце файла — метаданные. Если условие запроса несовместимо с диапазоном значений полосы, читатель может пропустить её. Аналогия с Parquet помогает: row group и stripe оба позволяют работать с частью большого файла, но их внутренний формат различается. Ни Parquet, ни ORC сами по себе не определяют, какие файлы входят в текущую таблицу, как атомарно обновить набор или кому он доступен.

ФорматГде часто удобенЧто проверить перед выбором
CSVПростая выгрузка фиксированных полей, обмен с внешней системойРазделитель, кавычки, кодировка, NULL, дата и типы не очевидны
JSON / JSON LinesСобытия с вложенными и меняющимися полямиВерсии протокола, типы, объём, частичный или повреждённый файл
AvroПередача структурированных записей со схемой, потоковые событияГде хранится схема, совместимость версий, кто её меняет
ParquetЧастые выборки отдельных колонок и агрегатыРазмер файлов и групп строк, типы, статистика, поддержка движком
ORCАналитическое колоночное хранениеПоддержка нужным движком, статистика и конкретный профиль запросов

Avro — формат с явной схемой записи и механизмами сопоставления схемы записи и чтения. Если к событию добавили необязательное поле temperature, читатель старой версии может продолжать обрабатывать известные поля при корректно заданной совместимости. Но наличие схемы не объясняет бизнес-значение: battery=72 всё ещё может означать проценты, а 0.72 — долю. Единицы и версия протокола остаются частью контракта.

Как выбирать для одной цепочки

Для поступления телеметрии можно сохранять исходный JSON Lines или Avro, если источник уже передаёт события по схеме. После проверки версии протокола построить Parquet с battery_pct, event_time_utc и vehicle_id. Аналитик, считающий средний заряд по дням, читает только нужные колонки. Инженер, выясняющий ошибку конкретного устройства, при необходимости возвращается к исходному сообщению. Фотографии остаются отдельными объектами; в таблице достаточно ключа объекта и описания связи с событием.

Для маленькой выгрузки в тысячу строк CSV может быть вполне достаточен. Нет смысла превращать любой файл в Parquet только потому, что проект называется Data Lake. Но при регулярных сканированиях миллиардов записей разница между чтением всех полей текста и нужных колонок становится существенной.

Как пропустить ненужные файлы

Представим подготовленные события за год, разложенные по дню: day=2026-09-01/part-001.parquet, day=2026-09-02/part-001.parquet и так далее. Запрос за 1 сентября может выбрать только соответствующий раздел — партицию — и не открывать файлы других дней. Это экономит чтение до того, как Parquet начнёт выбирать нужные колонки внутри файла. Но если запрос фильтрует по дате события, а разделы названы по дате загрузки, он может пропустить нужное позднее событие. Значение партиции и её смысл должны быть описаны.

Фильтр по 30 июня выбирает только раздел этого дня

Теперь соединим уровни на одном запросе. Предположим, в файле за 1 сентября две группы строк: у первой battery_pct от 10 до 45, у второй — от 50 до 95. Ищем средний заряд среди событий с зарядом не ниже 70%.

SELECT AVG(battery_pct) AS avg_battery_pct
FROM telemetry
WHERE day = DATE '2026-09-01'
  AND battery_pct >= 70;

Здесь day — колонка раздела, соответствующая каталогу. Мы предполагаем, что раздел построен по дате события, а не по дате загрузки: иначе позднее событие могло попасть в другой каталог.

ШагЧто исключаетсяОткуда берётся решение
Выбор разделаФайлы за другие дниday = 2026-09-01 и расположение файлов по дням
Пропуск группы строкПервая группа за 1 сентября: её максимум 45 меньше 70max(battery_pct) в метаданных группы
Выбор колонокКоординаты, текст ошибки и другие поля второй группыЗапрос использует только battery_pct; day уже известен из раздела
Проверка строкЗначения 50–69 во второй группеПосле чтения оставшейся колонки применяется точный фильтр

Границы min/max помогают решить, где точно нет подходящих значений; они не заменяют проверку каждой прочитанной строки. Пропуск может не сработать, если статистику не записали, типы не согласованы или конкретный читатель не умеет применить фильтр. Выбор файлов относится к устройству набора данных, а выбор колонок и статистика — к содержимому Parquet-файла.

Другая крайность — по одному файлу на каждое событие. На открытие и учёт тысяч маленьких файлов может уйти больше времени, чем на чтение их данных. Тогда несколько маленьких частей объединяют в более крупные, сохраняя ту же логическую таблицу. Универсального размера файла нет: он зависит от объёма, способа записи и движка чтения.

Когда меняется схема

Если новая версия устройства добавила temperature_c, старые файлы не обязаны внезапно получить эту колонку. Читатель может трактовать отсутствие как NULL, если это допустимо для задачи. Но если поле battery осталось числом, а его единица изменилась с доли на процент, автоматическое объединение схем не спасёт. Нужны версия протокола и явное преобразование: 0.72 и 72 должны стать одним battery_pct=72. Исходные файлы позволяют пересчитать набор после исправления правила.

Попробуйте на данных

lake_files описывает файлы, которые лежат в разных зонах и форматах. Для запроса по двум колонкам и одной дате сначала отберите нужный раздел и подготовленную зону:

SELECT object_key, format, size_bytes
FROM lake_files
WHERE zone = 'prepared' AND partition_day = '2026-06-30'
ORDER BY object_key;

SQL здесь читает метаданные, а не содержимое Parquet. Задания помогут заметить много мелких файлов и выбрать входы для конкретного чтения. CSV не становится плохим форматом во всех случаях: решение зависит от объёма и способа использования.

postgresql · песочницарешено 0 / 3

Для чтения подготовленных данных 30 июня выберите только Parquet-файлы этой даты. Верните object_key и size_bytes по ключу.

Ctrl+Enter
Войти, чтобы отмечатьдальше →
7.8 →Каталог и версии данных в озере