Перейти к содержанию
Learning Platform
Глоссарий Troubleshooting
Урок 03.03 · 30 мин
Средний
ParquetPagesData PageDictionary PageCompressionPage Header

Pages

Column Chunk состоит из страниц

Column chunk — это не монолитный блок. Внутри он разбит на страницы (pages) — минимальную единицу кодирования и компрессии. Каждая страница содержит подмножество значений колонки и может быть декомпрессирована независимо.

Три типа страниц:

  • Dictionary Page — словарь уникальных значений (не более одной на column chunk)
  • Data Page — закодированные значения (основной тип, их может быть много)
  • Index Page — зарезервирован в спецификации, на практике не используется
Типы страниц внутри Column Chunk

Column Chunk: department (BYTE_ARRAY)

Page Header (тип, размеры, num_values)

Page Header (Thrift): тип страницы, размер до/после компрессии, количество значений. Всегда идёт первым перед данными страницы.
Dictionary PageСловарь уникальных значений колонки. Для department: ['Engineering', 'Sales', 'HR', ...]. Максимум одна на column chunk. Если есть — всегда первая.
Data Page 0Первые N значений колонки. При dictionary encoding — массив целочисленных индексов: [0, 0, 1, 0, 2, 0, 1, ...]. Каждый индекс ссылается на dictionary page.
Data Page 1Следующая порция значений. Каждая data page сжимается независимо — можно декодировать одну страницу без чтения остальных.
Data Page NПоследняя data page может содержать меньше значений. Количество страниц зависит от data_page_size (дефолт 1 MB).

Data Page v1 vs v2

Parquet определяет две версии data page с принципиально разным подходом к компрессии.

Data Page v1 (DATA_PAGE)

Repetition levels, definition levels и закодированные значения сжимаются вместе как единый блок:

[Page Header]
[Compressed Block:
 repetition levels
 <Icon name="check" className="text-emerald-400" size="1.2em" /> definition levels
 <Icon name="check" className="text-emerald-400" size="1.2em" /> encoded values
]

Чтобы прочитать только levels (для пропуска страницы) — нужно декомпрессировать всю страницу.

Data Page v2 (DATA_PAGE_V2)

Levels хранятся отдельно от значений и не сжимаются. Компрессия применяется только к encoded values:

[Page Header (с длинами levels)]
[Repetition Levels — uncompressed]
[Definition Levels — uncompressed]
[Encoded Values — compressed]
Data Page v1 vs v2: структура компрессии

v1: всё сжато вместе

Page Header

Thrift-сериализованный заголовок. Содержит uncompressed_page_size, compressed_page_size, num_values, encoding.
Compressed BlockОдин блок: rep levels + def levels + values. Чтобы прочитать levels, нужно декомпрессировать всё. Простой формат, но неэффективный для page skipping.

Нельзя прочитать levels без декомпрессии

v2: levels отдельно

Page Header v2

Расширенный заголовок: добавлены repetition_levels_byte_length и definition_levels_byte_length — точные размеры секций.
Repetition LevelsRLE-закодированные, но не сжатые. Можно прочитать для определения границ записей без декомпрессии values.
Definition LevelsАналогично — RLE без компрессии. Позволяет определить null-позиции без декомпрессии данных.
Encoded ValuesТолько значения сжаты кодеком (Snappy/Zstd/LZ4). Levels доступны мгновенно — ключевое преимущество v2.

Levels доступны без декомпрессии

TIP

Data Page v2 особенно полезен для вложенных данных (nested structures), где repetition/definition levels критичны для навигации. Для плоских таблиц без NULL разница минимальна — levels занимают 0 байт.

Dictionary Page

Dictionary Page содержит упорядоченный список уникальных значений колонки. Data pages при dictionary encoding хранят только целочисленные индексы в этот словарь.

Правила:

  • Максимум одна dictionary page на column chunk
  • Если есть — всегда первая страница в chunk
  • Fallback: если словарь превышает dictionary_page_size_limit (обычно 1 MB) — writer переключается на PLAIN encoding
Роль Dictionary Page

С Dictionary

Dictionary PageМассив уникальных строк. Каждому значению присвоен целочисленный индекс. Для 10 уникальных department — 10 записей.
Data pages хранят индексы
Data Page (1M значений)Вместо строк — массив int32 индексов [0, 0, 1, 0, 2, ...]. RLE дополнительно сжимает повторяющиеся индексы.
10 уникальных из 1M строк → ~2 MB

Без Dictionary (PLAIN)

Data Page (1M значений)Каждое значение хранится целиком: 'Engineering' повторяется 400 000 раз, каждый раз ~11 байт. Огромный waste.
1M строк по ~10 символов → ~45 MB

Dictionary encoding даёт 20x+ сжатие для колонок с низкой кардинальностью (status, country, category). Для колонок с высокой кардинальностью (UUID, timestamp) словарь бесполезен — writer автоматически переключается на PLAIN.

Каждая страница начинается с Thrift-сериализованного заголовка. Формат зависит от типа страницы:

ПолеData Page v1Data Page v2Dictionary Page
typeDATA_PAGEDATA_PAGE_V2DICTIONARY_PAGE
uncompressed_page_size
compressed_page_size
num_values
encoding
definition_levels_byte_length
repetition_levels_byte_length
is_compressed
statistics(legacy)(legacy)
WARNING

Поле statistics в page header считается legacy. Современные ридеры используют ColumnIndex и OffsetIndex из File Metadata для page-level statistics — они эффективнее, потому что не требуют чтения заголовков каждой страницы.

Размер страницы: trade-offs

Размер data page настраивается параметром data_page_size (дефолт 1 MB в большинстве writers):

Маленькая страница (64 KB)Стандартная (1 MB)Большая страница (8 MB)
Точный page-level skipping Хороший баланс Лучшая компрессия
Больше page headers Дефолт везде Грубый skipping
Хуже компрессия Достаточная точность Больше памяти на декодирование

Маленькие страницы улучшают page-level predicate pushdown (ColumnIndex/OffsetIndex). Но если данные не отсортированы — page skipping всё равно неэффективен, и мелкие страницы лишь увеличивают overhead.

Ключевые выводы

  1. Page — минимальная единица кодирования и компрессии внутри column chunk
  2. Dictionary Page (максимум одна) хранит словарь уникальных значений; data pages ссылаются на него индексами
  3. Data Page v1 — levels + values сжаты вместе; v2 — levels отдельно (доступны без декомпрессии)
  4. Page Header (Thrift) содержит тип, размеры, encoding, количество значений
  5. data_page_size (дефолт 1 MB) контролирует гранулярность: мелкие страницы → точнее skipping, крупнее → лучше компрессия

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 7