Parquet или CSV: формат для таблиц и аналитики — выбор сводится к природе данных. CSV остаётся текстовым соглашением: строки, разделители, правила кавычек. Parquet — типизированное колоночное хранение с описанием схемы внутри файла. Ниже — разбор одного учебного набора, контракт типов и матрица выбора.
CSV как текст, Parquet как типизированное хранение
Документация Apache Parquet описывает формат как открытый колоночный формат файлов, созданный для эффективного хранения и извлечения данных; он предоставляет схемы сжатия и кодирования для объёмных данных и поддерживается во многих языках и аналитических инструментах (https://parquet.apache.org/docs/overview/). Ключевое слово здесь — «колоночный»: значения одного столбца лежат рядом, что даёт читателю возможность запрашивать подмножество столбцов.
Документация Arrow по CSV описывает получение имён столбцов из первой строки и вывод типов при чтении (https://arrow.apache.org/docs/python/csv.html). Сам CSV содержит текст; типы определяются читателем по правилам или задаются явно.
Практическое следствие: CSV хранит символы, Parquet хранит значения вместе со схемой. Когда вы передаёте CSV коллеге, вы передаёте текст и договорённость о том, как этот текст читать. Когда вы сохраняете Parquet, схема едет внутри файла, и читатель получает её из метаданных.
Полная CSV-строка с запятой, нулями и пропусками
Возьмём условный учебный набор. Его значения заданы для разбора:
order_id,amount,note
001,10.5,"a,b"
002,,
003,0,
Здесь три строки данных и три ловушки.
Первая — запятая внутри поля. У заказа 001 в note лежит a,b. Документация pandas по read_csv фиксирует правило: элементы в кавычках могут содержать разделитель, и он игнорируется (https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html). Без кавычек строка распалась бы на четыре поля, и парсер либо сдвинул бы столбцы, либо упал на несоответствии числа полей.
Вторая — ведущие нули. order_id записан как 001. Документация Arrow по CSV прямо разбирает этот случай: значения в кавычках всё равно проходят вывод типов, и чтобы сохранить форматирование вроде ведущих нулей, тип столбца задают явно как string (https://arrow.apache.org/docs/python/csv.html). При автоматическом выводе 001 станет числом 1, и обратная запись даст 1. Идентификатор заказа изменится.
Третья — пропуски. У заказа 002 пусты и amount, и note. У заказа 003 amount равен 0, а note пуст. В текстовом файле ,, и ,0, выглядят как обычные пустые поля.
Документация pandas добавляет: если keep_default_na равен False и na_values не заданы, ни одна строка не будет разобрана как NaN (https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html). Это рычаг управления, но он глобальный для чтения. Он не различает пустую строку и отсутствие значения — он решает, считать ли пустое поле пропуском вообще.
Один контракт типов для обоих форматов
Контракт исходной таблицы для нашего примера выглядит так:
| Столбец | Тип | Правило |
|---|---|---|
order_id |
string | ведущие нули значимы, 001 остаётся 001 |
amount |
double, nullable | число или отсутствие значения |
note |
string, nullable | текст, пустая строка или отсутствие значения |
Этот контракт работает для обоих форматов. Разница в том, где он живёт. В Parquet он записывается в схему файла: order_id:string, amount:double nullable, note:string nullable. В CSV он живёт во внешнем документе, в коде читателя или в голове отправителя.
Для CSV документация Arrow предлагает column_types для типов столбцов и null_values для маркеров пропуска (https://arrow.apache.org/docs/python/csv.html). В pandas используются dtype, na_values и keep_default_na; указанные converters применяются вместо преобразования dtype (https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html).
Практический вывод: контракт типов пишется один раз и переносится в оба формата. Меняется носитель — схема файла или параметры читателя.
Пустая строка и null без соглашения
В нашем CSV у заказа 002 note пуст, и у заказа 003 note пуст. Символьно это одно и то же: между двумя запятыми ничего нет. Восстановить, где была пустая строка, а где отсутствие значения, из файла невозможно. Нужно внешнее соглашение.
В Parquet исходная схема различает эти случаи: значения note записаны как ["a,b", "", None]. Пустая строка и None — разные значения одного nullable-столбца.
Документация pandas по read_csv объясняет механику на стороне CSV: распознанные как отсутствующие значения читаются как NaN или NA-значение типа, независимо от указанного dtype (https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html). То есть по умолчанию пустое поле становится пропуском. Пустая строка как отдельное значение требует настройки: отключения стандартного набора пропусков через keep_default_na=False и явного перечисления того, что считать пропуском.
Отсюда два разных соглашения, и выбрать надо одно:
- Пустое поле означает отсутствие значения. Тогда пустая строка в данных неотличима от пропуска, и её нельзя сохранить в CSV без маркера.
- Пустое поле означает пустую строку. Тогда отсутствие значения кодируется отдельным маркером, например
NULLили\N, и этот маркер перечисляется вna_values.
Документация Arrow даёт третий рычаг: strings_can_be_null и quoted_strings_can_be_null в ConvertOptions управляют тем, могут ли строковые и бинарные столбцы иметь пропуски и могут ли пропусками быть значения в кавычках (https://arrow.apache.org/docs/python/csv.html). Для такого различения в Arrow задайте null_values=[""], strings_can_be_null=True и quoted_strings_can_be_null=False: тогда "" сохраняется как пустая строка, а пустое поле без кавычек становится пропуском. Это соглашение, и его надо зафиксировать до обмена.
Выбор столбцов и фильтрация: reader и статистики
Колоночная раскладка даёт эффект только тогда, когда читатель умеет им пользоваться. Документация Arrow по Parquet формулирует прямо: можно передать подмножество столбцов для чтения, и это может быть существенно быстрее чтения всего файла благодаря колоночной раскладке (https://arrow.apache.org/docs/python/parquet/parquet.html). Там же отмечено ограничение: данные Parquet нужно декодировать из формата и распаковывать, поэтому напрямую с диска они не отображаются (https://arrow.apache.org/docs/python/parquet/parquet.html).
Фильтрация опирается на статистики. Документация Amazon Athena описывает predicate pushdown: в Parquet и ORC он позволяет запросам Athena выбирать только нужные блоки, улучшая производительность запроса (https://docs.aws.amazon.com/athena/latest/ug/columnar-storage.html). Это утверждение про Athena и про форматы Parquet и ORC в её контексте.
Для CSV аналогичные возможности зависят от читателя. Документация Arrow перечисляет include_columns — имена столбцов, включаемых в таблицу, и include_missing_columns, который при значении false вызывает ошибку, если столбец из include_columns отсутствует в CSV-файле (https://arrow.apache.org/docs/python/csv.html). Отбор столбцов на входе экономит память, но чтение всё равно проходит по строкам файла: чтобы добраться до нужного столбца, парсер разбирает всю строку.
Практическое правило: проверяйте возможности конкретного reader. Наличие параметра отбора столбцов в библиотеке не означает, что фильтрация по значениям дойдёт до уровня блоков файла.
Матрица трёх сценариев выбора
| Сценарий | Формат | Что зафиксировать |
|---|---|---|
| Ручной обмен с человеком | CSV | контракт типов, правило кавычек, маркер пропуска |
| Повторная аналитика по части столбцов | Parquet | схему, подходящий reader, проверку nullable-типов |
| Получатель принимает только CSV | CSV | явную схему и согласованный маркер пропуска |
Первый сценарий: файл открывают в таблице или редакторе. CSV читается глазами, Parquet требует инструмента. Отдавайте CSV вместе с описанием контракта: какие столбцы строковые, где допустимы пропуски, как кодируется отсутствие значения.
Второй сценарий: данные читаются многократно, а запросы затрагивают часть столбцов. Рассмотрите Parquet с подходящим reader и проверьте сохранение типов на одном полном цикле записи и чтения.
Третий сценарий: получатель работает только с CSV. Передайте вместе с файлом контракт типов и маркер пропуска, затем согласуйте параметры чтения на его стороне.
Проверка round trip и разбор ошибок
Две проверки в нашем примере независимы. Первая: ведущие нули в 001. Вторая: различие null и пустой строки. Даже если Parquet сохранил схему, нужно проверить перенос nullable-типов в целевой инструмент. Размеры файлов и скорость в этом разборе не измерялись.
Порядок проверки для обоих форматов:
- Запишите исходную таблицу с известными значениями:
order_idсо ведущими нулями,amountс числом и пропуском,noteс текстом, пустой строкой и пропуском. - Прочитайте файл тем же инструментом, которым будете читать в работе.
- Сравните
order_idпосимвольно.001совпадает с001,1— расхождение. - Сравните
noteпо трём позициям: текст, пустая строка, пропуск. Совпадение по всем трём означает, что соглашение работает. - Сравните
amount: число сохранило значение, пропуск остался пропуском.
Частые причины расхождений. Автоматический вывод типов превращает 001 в 1 — лечится явным указанием строкового типа. Стандартный набор пропусков читает пустую строку как отсутствие значения — лечится настройкой na_values и keep_default_na. Читатель Parquet не поддерживает нужный логический тип — обзор Apache Parquet отмечает, что не все реализации поддерживают одни и те же возможности формата, и при интеграции нескольких реализаций важно проверять совместимость и производительность (https://parquet.apache.org/docs/overview/).
Частые вопросы
Parquet или CSV: что быстрее читается?
Скорость зависит от читателя, данных и выбранных столбцов. Документация Arrow указывает, что отбор части столбцов Parquet может ускорить чтение. Для выбора сравните одинаковую задачу на своих файлах и зафиксируйте условия измерения.
Почему из CSV пропадают ведущие нули?
Автоматический вывод типов может прочитать 001 как число. Явно задайте строковый тип order_id, затем проверьте значения после чтения и обратной записи. Одних кавычек вокруг идентификатора недостаточно.
Как отличить пустую строку от пропуска в CSV?
Задайте отдельный маркер пропуска и согласуйте параметры na_values и keep_default_na. Пустая строка и пропуск должны иметь разные представления; проверьте оба случая после обратного чтения.
Parquet сжимает файлы сильнее CSV?
Итоговый размер зависит от данных, схемы, кодирования и алгоритма сжатия. CSV тоже можно передавать в сжатом потоке. Выберите поддерживаемый получателем вариант и сравните размеры на своём наборе.
Можно ли читать только нужные столбцы из Parquet?
Да, если reader поддерживает выбор столбцов при чтении. Проверяйте эту возможность отдельно от фильтрации строк по значениям: для неё важны predicate pushdown и подходящие метаданные файла.
