Интерактивный Parquet File Viewer
Зачем нужен File Viewer
В предыдущих уроках мы изучили каждый слой отдельно: row groups, column chunks, pages, encodings, metadata. Теперь соберём все вместе — в интерактивном viewer, который показывает реальную структуру Parquet-файла.
Viewer ниже представляет файл с 200 000 строк в 2 row groups по 3 колонки (user_id: INT64, username: BYTE_ARRAY, score: DOUBLE). Это типичная структура, которую вы увидите при инспекции реального файла через pyarrow.parquet.read_metadata().
Кликайте на Row Groups и Column Chunks, чтобы раскрыть их содержимое.
Как читать viewer
Уровень файла
Верхний блок — файловые метаданные. Здесь вы видите:
- PAR1 — 4-байтовая магическая сигнатура в начале и конце файла
- version — версия формата Parquet (v2 = поддержка Data Page V2, ColumnIndex)
- rows — общее количество строк в файле
- schema — типы колонок в Thrift-нотации
Конец файла: PAR1 + metadata length
Reader начинает с конца файла. Читает последние 8 байт: 4 байта metadata length + 4 байта PAR1. Это даёт offset footer.Footer: FileMetaData (Thrift)
По metadata length reader вычисляет offset и читает Thrift-сериализованный FileMetaData. Это единственный I/O для метаданных — один запрос.Планирование чтения: какие chunks читать
Из FileMetaData reader узнаёт: количество row groups, offset каждого column chunk, схему, статистики. Всё остальное — point reads по offset.Уровень Row Group
Раскройте Row Group в viewer. Вы увидите:
- rows — количество строк в этой группе (100 000)
- size — общий размер несжатых данных (2.5 MB)
- columns — количество column chunks (3 — по одному на колонку)
Каждый row group содержит полный набор column chunks для своего диапазона строк.
Уровень Column Chunk
Раскройте любой column chunk. Обратите внимание:
- offset — позиция в файле в hex (например,
0x4= 4 байта от начала). Это byte offset, по которому reader находит данные - comp — сжатый размер. Сравните с ratio — это коэффициент сжатия (raw / compressed)
- min/max — chunk-level статистики для predicate pushdown
- enc — используемые кодировки (RLE_DICTIONARY + PLAIN для
user_id, BYTE_STREAM_SPLIT дляscore) - nulls — количество null-значений (
usernameимеет 12 null в Row Group 0)
Уровень Page
Раскройте column chunk дальше — вы увидите отдельные страницы:
- DICTIONARY — словарная страница (если кодировка RLE_DICTIONARY). Всегда первая в chunk. Содержит уникальные значения
- DATA_PAGE_V2 — страницы данных. Каждая содержит закодированные значения для порции строк
- min/max на каждой data page — это page-level статистики из ColumnIndex
Обратите внимание: колонка score (DOUBLE) не имеет dictionary page — она использует BYTE_STREAM_SPLIT, который кодирует float/double напрямую без словаря. А user_id и username начинаются с DICTIONARY_PAGE, за которой следуют DATA_PAGE_V2 с индексами в словарь.
Инспекция реального файла
В viewer мы используем захардкоженные данные. В реальной работе вы будете инспектировать файлы через PyArrow:
import pyarrow.parquet as pq
# Метаданные файла
meta = pq.read_metadata('users.parquet')
print(f"Rows: {meta.num_rows}")
print(f"Row groups: {meta.num_row_groups}")
print(f"Format: {meta.format_version}")
print(f"Created by: {meta.created_by}")
# Метаданные row group
rg = meta.row_group(0)
print(f"RG 0: {rg.num_rows} rows, {rg.total_byte_size} bytes")
# Метаданные column chunk
col = rg.column(0)
print(f"Column: {col.path_in_schema}")
print(f"Codec: {col.compression}")
print(f"Encodings: {col.encodings}")
print(f"Stats: min={col.statistics.min}, max={col.statistics.max}")
print(f"Nulls: {col.statistics.null_count}")
FileMetaData
FileMetaData объект. .num_rows, .num_row_groups, .schema, .format_version, .created_by, .serialized_size, .metadata (key-value)pq.read_metadata() не загружает данные — только footer. Это единственный I/O, необходимый для инспекции файла. На S3/GCS это один Range Read. Для быстрой проверки структуры файла в production — это штатный инструмент.
Паттерны для инспекции
| Задача | Команда / API |
|---|---|
| Размер row groups | meta.row_group(i).total_byte_size |
| Кодировки колонки | rg.column(j).encodings |
| Статистики для pruning | rg.column(j).statistics.min / .max |
| Null count | rg.column(j).statistics.null_count |
| Compression ratio | compressed_size / uncompressed_size |
| Схема файла | pf = pq.ParquetFile('f.parquet'); pf.schema_arrow |
Ключевые выводы
- Viewer показывает все уровни одновременно: File → Row Groups → Column Chunks → Pages с byte offsets и статистиками
- Byte offsets — ключ к пониманию физического layout: chunks идут последовательно, каждый начинается по offset из metadata
- Compression ratio сильно зависит от типа данных: INT64 (1.9×), strings (1.5×), DOUBLE с BYTE_STREAM_SPLIT (1.2×)
- Dictionary vs no dictionary: integer и string колонки с low cardinality используют RLE_DICTIONARY, float/double — BYTE_STREAM_SPLIT
- В реальной работе используйте
pq.read_metadata()— один I/O вызов для полной инспекции структуры файла