Stripes и физическая структура
Структура ORC-файла
ORC (Optimized Row Columnar) — колоночный формат, созданный в экосистеме Hive. Физическая структура отличается от Parquet: магическая сигнатура короче, метаданные сериализованы через Protocol Buffers (не Thrift), а чтение файла начинается с последнего байта — PostScript.
Файл начинается с 3-байтовой сигнатуры ORC (hex: 4F 52 43). Обратите внимание — это 3 байта, а не 4 как PAR1 у Parquet. После сигнатуры идут stripes с данными, а в конце — Footer, Metadata и PostScript.
Footer (Protobuf-encoded)
Protobuf-сериализованная структура Footer: схема типов (type tree), stripe information, статистики по колонкам, user metadata.File Metadata (Protobuf-encoded)
Protobuf-сериализованная структура Metadata: stripe-level статистики (column stats per stripe). Опциональная — может быть пустой.PostScript (последний элемент файла)
Последний элемент файла. НЕ Protobuf — чистые байты фиксированного формата. Содержит длины Footer и Metadata, версию, кодек компрессии, magic 'ORC'. Размер PostScript — последний байт файла.ORC-ридер открывает файл с последнего байта: этот единственный байт содержит длину PostScript. Далее ридер читает PostScript, из него — длины Footer и Metadata, затем подтягивает структуры по offset. Только после этого он знает схему, количество stripes и расположение данных.
Чтение ORC-файла: с конца к началу
Алгоритм чтения — ключевая деталь, которая объясняет, почему метаданные в конце файла:
- Читаем последний байт → длина PostScript (1 байт, unsigned)
- Читаем PostScript → version, compression, footer length, metadata length, magic
- Вычисляем offset Footer = fileSize - 1 - postScriptLength - footerLength
- Читаем Footer → schema (type tree), stripe information, file statistics
- (Опционально) читаем Metadata → stripe-level column statistics
- По stripe information из Footer переходим к нужным stripes
Порядок чтения
① Последний байт → длина PostScript
Шаг 1: читаем ровно 1 байт с конца файла. Значение 0–255 — длина PostScript в байтах.② PostScript → version, codec, lengths
Шаг 2: читаем PostScript — фиксированная структура без Protobuf. Содержит magic 'ORC', version, compression codec, длины Footer и Metadata.③ Footer → schema, stripes, statistics
Шаг 3: по длине из PostScript вычисляем offset и декодируем Protobuf-структуру Footer.④ Seek к нужной stripe → данные
Шаг 4: по stripe offsets из Footer — прямой seek к нужной stripe. Lazy reading — читаем только то, что запрошено.Сравнение с Parquet
ORC использует промежуточный PostScript для Bootstrap — это позволяет хранить кодек компрессии до чтения Footer (Footer сам может быть сжат)
PostScript — единственная структура в ORC-файле, которая никогда не сжимается. Footer и Metadata сжимаются кодеком, указанным в PostScript. Если бы PostScript тоже был сжат, возник бы chicken-and-egg problem: нужно знать кодек, чтобы разжать, но кодек записан в сжатой структуре.
Stripe: основная единица данных
Stripe в ORC аналогична Row Group в Parquet — это горизонтальный срез таблицы, содержащий все колонки для порции строк. Но внутренняя структура stripe более детализирована: каждая stripe содержит три секции.
| Секция | Содержимое | Назначение |
|---|---|---|
| Index Data | Row index streams + bloom filter streams | Предикатное отсечение, seek к row group |
| Row Data | Column data streams (per-column) | Фактические данные колонок |
| Stripe Footer | Stream directory + column encodings | Карта потоков внутри stripe |
Размер Stripe: настройки
Размер stripe — настраиваемый параметр, влияющий на параллелизм, I/O и использование памяти. Два ключевых значения по умолчанию:
- ORC library (Java/C++ reference): 64 MB
- Hive: 250 MB (конфигурация
hive.exec.orc.default.stripe.size)
Маленькая stripe (16–32 MB)
Маленькие stripes (16–32 MB): больше параллелизма, точнее predicate pushdown, но больше overhead индексов и footer. Больше параллелизма
Точнее predicate pushdown
Больше index / footer overhead
Больше seek операций
Стандартная stripe (64 MB)
Стандартный размер 64 MB (ORC lib). Баланс между параллелизмом и overhead. Достаточно для HDFS блока (128 MB = 2 stripes). Хороший баланс
2 stripes на HDFS блок
Достаточная компрессия
Дефолт ORC library
Большая stripe (250 MB)
Большие stripes (250 MB, дефолт Hive): лучшая компрессия, меньше overhead, но грубый параллелизм и большее потребление памяти. Лучшая компрессия
Меньше overhead
Грубый параллелизм
Больше памяти на чтение
| Инструмент | Параметр | Значение по умолчанию |
|---|---|---|
| ORC Java library | orc.stripe.size | 64 MB |
| Hive | hive.exec.orc.default.stripe.size | 256 MB |
| Spark (ORC) | orc.stripe.size | 64 MB |
| Presto / Trino | orc.max-buffer-size | 8 MB (buffer, не stripe) |
PostScript: bootstrap-структура
PostScript — точка входа при чтении файла. Это единственная структура, которая не сжимается и не сериализуется через Protobuf. Она содержит минимум информации, необходимый для начала парсинга:
message PostScript {
footerLength: uint64 // длина Footer в байтах
compression: CompressionKind // NONE, ZLIB, SNAPPY, LZO, LZ4, ZSTD
compressionBlockSize: uint64 // размер блока компрессии (дефолт 256 KB)
version: [uint32] // [0, 12] для Hive 0.12+
metadataLength: uint64 // длина File Metadata в байтах
magic: string // "ORC"
}
Поле version — массив из двух элементов: [major, minor]. Версия [0, 11] означает Hive 0.11 (v0 формат с RLEv1). Версия [0, 12] — Hive 0.12+ (v1 формат с RLEv2, индексами и bloom filters). Текущий production-формат — v1 ([0, 12]).
Footer: схема и метаданные
Footer — главная Protobuf-структура файла. Содержит три ключевых блока:
- Type tree — схема файла в виде дерева типов (подробнее в уроке 04)
- Stripe Information — offset, length, row count для каждой stripe
- File Statistics — агрегированные min/max/count по каждой колонке (для всего файла)
message Footer {
headerLength: uint64
contentLength: uint64
types: [Type] // дерево типов
stripes: [StripeInformation]
metadata: [UserMetadataItem] // key-value пользовательские метаданные
numberOfRows: uint64
statistics: [ColumnStatistics] // per-column stats для всего файла
rowIndexStride: uint32 // default 10 000
}
Сравнение с Parquet
| Характеристика | ORC | Parquet |
|---|---|---|
| Magic number | ORC (3 байта) | PAR1 (4 байта) |
| Сериализация метаданных | Protocol Buffers | Apache Thrift |
| Bootstrap-структура | PostScript (не сжат) | (footer length + PAR1) |
| Единица горизонтального деления | Stripe (64–250 MB) | Row Group (128 MB) |
| Расположение метаданных | PostScript + Footer + Metadata | FileMetaData (одна структура) |
| Компрессия метаданных | Footer и Metadata сжаты | Footer не сжат |
| Количество read-операций для открытия | 2–3 (PostScript → Footer → Metadata) | 1–2 (footer length → FileMetaData) |
Ключевые выводы
- ORC-файл начинается с 3-байтовой сигнатуры
ORC(hex:4F 52 43) и читается с конца - PostScript — единственная несжатая структура, содержит кодек компрессии и длины Footer/Metadata
- Stripe — основная единица данных (аналог Row Group), содержит Index Data, Row Data и Stripe Footer
- Размер stripe по умолчанию: 64 MB (ORC lib) или 250 MB (Hive)
- Метаданные сериализованы через Protocol Buffers (Parquet использует Thrift)
- Footer содержит type tree, stripe information и file-level statistics