BtrBlocks: каскадное кодирование
В Модуле 08, Урок 06 мы увидели, как разные системы выбирают кодировки: Parquet — probe-and-fallback, ORC — statistics-driven, DuckDB — sample-based. Каждая из них выбирает одну кодировку на блок.
BtrBlocks (SIGMOD 2023, Kuschewski, Sauerwein, Alhomssi, Leis — TU Munich) задаёт вопрос: а что если применить несколько кодировок подряд? Выход одной кодировки становится входом другой — каскад. Dictionary сначала заменяет строки на индексы, затем FOR сжимает индексы, затем BitPacking упаковывает результат. Каждый уровень каскада добавляет сжатие, потому что работает с данными, уже упрощёнными предыдущим уровнем.
Идея: sampling + cascade
Вместо выбора одной “лучшей” кодировки BtrBlocks:
- Берёт sample (1–5%) данных из блока
- Пробует каждую из 8 кодировок на sample
- Выбирает лучшую → применяет к полным данным
- На выход первой кодировки — снова пробует все кодировки из пула
- Повторяет, пока cascade не перестаёт улучшать ratio
Блок: 65K строк, 12 unique departments
Блок данных: 65 536 строковых значений (department names). Кардинальность: 12 уникальных значений. Распределение: 'Engineering' = 40%, 'Sales' = 20%, остальные 10 отделов по 4%.Chain: Dictionary → FOR. Total: ~33 KB. Ratio: ~23.6x
Финальная chain: Dictionary → FOR. Размер: 32.5 KB (offsets) + 120 B (dictionary) + metadata ≈ 33 KB. Original: 65K × ~12 bytes = ~780 KB. Ratio: 780/33 ≈ 23.6x. Для сравнения: single Dictionary без cascade = 65K × 4 bits = 32.5 KB (то же самое — FOR не добавил в этом случае, потому что indices уже компактны). Cascade выигрывает на более сложных данных.Когда cascade реально помогает
Cascade даёт выигрыш, когда выход первой кодировки имеет другую структуру, чем вход:
Cascade не всегда улучшает результат. На данных с максимальной энтропией (random bytes, encrypted) или уже оптимально закодированных (constant column) — cascade останавливается на Level 0. Стоимость cascade: O(sample_size × pool_size × levels) — но sample маленький (1–5%), pool фиксирован (8), levels обычно 2–3.
Пул кодировок: 8 encodings
BtrBlocks использует фиксированный пул из 8 кодировок. Каждая имеет свою роль в cascade:
Pseudodecimal Encoding: инновация для doubles
Pseudodecimal — наиболее неожиданная кодировка в пуле BtrBlocks. Наблюдение авторов: значительная часть double-колонок в реальных данных — это decimal числа (цены, проценты, температуры), хранимые как IEEE 754 double из-за отсутствия native decimal типа в большинстве систем.
Колонка: [3.25, 10.99, 7.50, 99.95, …] (double, 8 bytes each)
Колонка цен: $3.25, $10.99, $7.50, $99.95, ... Хранится как double (8 bytes each). IEEE 754: 3.25 = 0x4008000000000000. Высокая entropy — integer encodings не работают напрямую.Результат: 520 KB → 138 KB. Ratio: 3.8x (vs ~1.0x без Pseudodecimal)
Финальный результат: 65K × 17 bits = 138 KB + metadata (exponent=2, base=1, dict=none). Original: 65K × 64 bits = 520 KB. Ratio: 3.8x. Без Pseudodecimal: ratio ~1.0x (doubles несжимаемы стандартными integer encodings). Cascade chain: Pseudodecimal → FOR → BitPacking.Pseudodecimal vs ALP
Pseudodecimal в BtrBlocks и ALP в DuckDB — это одна и та же идея (decimal floats → integers) с разным уровнем зрелости. BtrBlocks первым опубликовал (SIGMOD 2023). ALP (SIGMOD 2024) добавил exception handling и second mode для non-decimal floats, и интегрирован в production DuckDB. Подробно ALP рассмотрим в Уроке 05.
Evaluation: Public BI Benchmark
BtrBlocks оценивался на Public BI Benchmark — коллекции реальных бизнес-данных из Tableau Public (73 таблицы, 5.7 млрд строк, ~860 GB raw):
Почему BtrBlocks выигрывает
BtrBlocks — исследовательский прототип, не production-ready формат. Нет экосистемы (Spark, Trino, DuckDB не читают BtrBlocks файлы), нет спецификации формата, нет governance. Ценность BtrBlocks — идеи: cascade encoding и Pseudodecimal уже влияют на DuckDB (ALP), и могут повлиять на будущие версии Parquet. GitHub: maxi-k/btrblocks, C++, MIT license.
BtrBlocks: архитектура формата
BtrBlocks File
BtrBlocks файл: columnar layout. Данные разбиты на блоки (chunks) по ~65K значений на колонку. Каждый chunk — независимая единица cascade encoding.Decode: chain в обратном порядке. Per-chunk parallel.
Decode: прочитать chain descriptor → применить decode в обратном порядке. Dict→FOR: un-FOR (add base to offsets) → un-Dictionary (lookup indices in dict). Per-chunk decode: полная параллелизация.Ключевые выводы
- BtrBlocks (SIGMOD 2023, TU Munich) — cascade encoding framework: выход одной кодировки → вход другой. 2–3 уровня cascade.
- Sampling-based selection: 1–5% sample → evaluate все 8 кодировок → лучшая → cascade → repeat. Быстро (sample маленький), эффективно (пробует все варианты).
- Пул из 8 кодировок: Uncompressed, OneValue, Dictionary, RLE, Frequency, Pseudodecimal, FOR, FSST. Каждая имеет роль в cascade (first / inner / terminal).
- Pseudodecimal Encoding: doubles с decimal значениями ($3.25) → integers (325). Делает doubles доступными для integer cascade. Предшественник ALP (SIGMOD 2024).
- Результаты: 7.5x compression (vs Parquet+Zstd 5.5x) при 2.0 GB/s decode (vs 1.0 GB/s). Лучше сжимает и быстрее декодирует.
- Причина: type-aware encodings + cascade + lightweight decode (bit operations вместо LZ77/ANS). Знание типа данных > brute-force general-purpose compression.
- Статус: research prototype (C++, MIT license). Идеи влияют на DuckDB (ALP, FSST). Не production format.