Learning Platform
Глоссарий Troubleshooting
Урок 16.05 · 40 мин
Продвинутый
VortexCompressed ComputeWhite-Box EncodingLate MaterializationFilter PushdownFastLanesSIMDGPU DecodeTPC-HIceberg Integration

Vortex Compressed Compute

В предыдущем уроке мы разобрали архитектуру Vortex: extensible encodings, layout tree, cascading compression. Теперь — главное преимущество: compressed compute — выполнение запросов без полной декомпрессии данных.

Традиционный pipeline: read → decompress → decode → compute. Vortex pipeline: read → compute on encoded. Разница — 5-20x по скорости и значительно меньший memory footprint.

White-Box Encodings

“White-box” — ключевой термин в архитектуре Vortex. В отличие от “black-box” компрессии (ZSTD, LZ4), где engine видит только compressed blob, Vortex encodings прозрачны для query engine:

Black-Box vs White-Box Encodings

Black-Box (Parquet + ZSTD)

Black-box compression (Parquet + ZSTD/LZ4): engine видит compressed blob. Для любой операции (filter, aggregate, projection) — сначала decompress. Engine не знает структуру сжатых данных. Compression algorithm = непрозрачная функция.
Engine видитCompressed bytes: непрозрачный blob. Нет информации о значениях без decompress. Невозможно: filter на compressed, aggregate на compressed, compare на compressed. Единственная операция: decompress → raw values.
Обязательный шагDecompress + decode — обязательный шаг перед любой операцией. ZSTD decompress: ~800 MB/s на одном ядре. Для 1GB column: ~1.2 секунды CPU time только на decompress, до начала compute.

White-Box (Vortex)

White-box encodings (Vortex): engine знает тип encoding'а и его параметры. Dictionary: engine знает словарь и может фильтровать по index. RLE: engine знает (value, count) pairs и может агрегировать без развёртывания. Delta: engine может compute на дельтах.
Engine видитStructured encoding: тип (Dictionary/RLE/ALP/...), параметры (словарь, run lengths, base+delta). Engine может интерпретировать encoding напрямую. Каждый encoding предоставляет compute API.
Compressed computeFilter на Dictionary: lookup value в словаре → index → bitmap scan на indices. Нет decompress. SUM на RLE: Σ(value × count). Нет развёртывания. SUM на Delta: base×N + Σ(deltas). Нет восстановления оригинальных значений.

Compressed Compute Operations

Каждый encoding в Vortex предоставляет compute traits — набор операций, выполнимых без декомпрессии:

Compute Traits per Encoding
EncodingТип кодировки в Vortex.
FilterМожно ли выполнить предикат (WHERE) без декомпрессии?
AggregateМожно ли выполнить агрегацию (SUM, COUNT, MIN, MAX) без декомпрессии?
ScanМожно ли читать значения последовательно без полной декомпрессии?
DictionaryDictionary encoding: значения → indices в словаре. Filter: lookup value в словаре → target index → bitmap scan по indices array. Aggregate: GROUP BY → group per dict index. Scan: sequential index → value lookup.
Equality (=): O(dict_size) lookup. IN (...): O(dict_size × list_size). LIKE: scan dict only (5-1000 entries vs 1M+ rows). Результат: bitmap на indices.
COUNT: length of indices array. COUNT(DISTINCT): dict_size. GROUP BY: group per dict index. MIN/MAX: scan dict (sorted → O(1)).
Sequential: iterate indices → dict lookup. Lazy: materialize only needed values. Batch: SIMD gather from dict.
RLERun-Length Encoding: (value, count) pairs. Sorted колонки: длинные runs. Filter: scan (value, count) pairs — гораздо меньше, чем raw rows. Aggregate: run-aware operations.
Equality: scan runs, return ranges where value matches. O(num_runs) — для sorted column with 1000 unique values in 1M rows: 1000 operations vs 1M. BETWEEN: binary search on run boundaries.
SUM: Σ(value × count) — одно умножение per run. COUNT: Σ(counts). MIN: min of run values (if sorted: first). MAX: max of run values (if sorted: last). Без развёртывания runs.
Sequential: emit value `count` times. Lazy: skip runs, materialize only requested range. Very efficient for range queries on sorted data.
DeltaDelta encoding: base + deltas. Для monotonic sequences: timestamps, auto-increment IDs. Compressed compute: operations на deltas без восстановления оригинальных значений.
Range (BETWEEN): check if base+cumsum(deltas) falls in range — partial scan. Equality: harder without prefix sum. Best for range predicates, not equality.
SUM: base×N + Σ(deltas) — два числа. MIN: base (if all deltas ≥ 0). MAX: base + Σ(deltas) (if sorted ascending). COUNT: N (trivial).
Sequential: base, base+Δ1, base+Δ1+Δ2, ... Prefix sum: O(N) scan. For sorted data: efficient binary search on cumulative sums.
ALPAdaptive Lossless floating-Point: float → integer extraction (19.99 → 1999, exp=-2). Compute на integers вместо floats — быстрее и точнее (нет float rounding errors).
Equality (= 19.99): multiply by 10^2 → compare integer 1999. Range: multiply bounds → integer range filter. Работает для ограниченного набора предикатов.
SUM: SUM(integers) × 10^exponent. Exact integer arithmetic вместо float accumulation. AVG: SUM(ints) / N × 10^exp. Нет float rounding drift.
Sequential: integer → float reconstruction per value. For bulk: vectorized multiply by 10^exp. SIMD-friendly integer arithmetic.
ConstantConstant encoding: все значения в chunk одинаковы. Хранится одно значение + count. Для partition columns, default values, sparse NULL columns (all null).
Equality: compare one value. O(1). Если value = target → все строки match. Если ≠ → ни одна. Идеальный case для partition pruning.
SUM = value × count. COUNT = count. MIN = MAX = value. Всё O(1). Идеальный encoding для aggregation — одно значение описывает весь chunk.
Emit same value N times. No storage read needed — value in metadata. Fastest possible scan.

Filter Pushdown в Storage

Vortex pushdown’ит фильтры внутрь encoding’а, не просто на уровень chunk statistics:

Filter Pushdown: три уровня глубины
WHERE country = 'DE' AND amount > 1000Запрос: WHERE country = 'DE' AND amount > 1000. Два предиката: equality на string + range на numeric. Vortex pushdown'ит оба максимально глубоко в encoding'и.
Level 1: Chunk Stats
Chunk PruningLevel 1: per-chunk statistics (min/max/null_count). country: min='AU', max='US' — chunk может содержать 'DE'. amount: min=500, max=9999 — chunk может содержать >1000. Оба условия — возможны → read chunk. Аналог Parquet row group pruning.
Level 2: Encoding-Aware
Dictionary FilterLevel 2: country колонка — Dictionary encoded (50 countries). Lookup 'DE' в словаре: index=7. Вместо сравнения 1M строк с 'DE': bitmap scan по indices = 7. O(dict_size + N_bitcheck) вместо O(N × strlen).
Level 3: Combine
Combined BitmapLevel 3: AND двух bitmap'ов. country_bitmap AND amount_bitmap → final selection. Только matching строки материализуются. Bitmap AND — SIMD operation, O(N/64) на 64-bit words.

Late Materialization

Vortex использует late materialization — откладывает декодирование до последнего момента:

Late Materialization: decode откладывается
SELECT name, email WHERE country='DE' AND age > 30Запрос: SELECT name, email FROM users WHERE country='DE' AND age > 30. Нужны 4 колонки: country (filter), age (filter), name (output), email (output). Наивный подход: decode все 4 → filter → project.

Eager (Parquet)

Eager materialization (Parquet): декодировать все 4 колонки сразу, применить filter, отбросить нерелевантные строки. Если filter отсекает 99% — 99% decode work потрачено впустую.
Decode ALLDecode: country (1M strings), age (1M int32), name (1M strings), email (1M strings). Total decode: ~4M values. Filter: 1% match (10K rows). Wasted: 3.96M decodes (99%). Если country 99.5% filtered + age ещё 50%: 0.25% финальный match.

Late (Vortex)

Late materialization (Vortex): сначала filter на encoded country и age → bitmap matching строк → decode name и email ТОЛЬКО для matching строк. Decode work пропорционален result size, не input size.
Filter → DecodeStep 1: filter country (dict lookup, no full decode) → bitmap_country. Step 2: filter age (encoded compare, partial decode) → bitmap_age. Step 3: AND bitmaps → 10K matching. Step 4: decode name + email ONLY for 10K rows. Total: 20K decodes (vs 4M).
TIP

Late materialization особенно эффективна для wide tables (50-100+ колонок) с selective predicates (filter отсекает >90%). Типичный OLAP сценарий: SELECT 3 колонки из 100 WHERE filter оставляет 1% строк. Eager: decode 100 × 1M. Late: filter на 2-3 encoded колонках → decode 3 × 10K. 1000x разница в decode work.

SIMD-Friendly Decode: FastLanes

Когда декомпрессия всё-таки нужна, Vortex использует FastLanes для максимальной скорости:

FastLanes: SIMD decode pipeline

BitPacked: 1M × 3 bits = 375KB

BitPacked данные: 1M значений × 3 bits = 375KB. Нужно распаковать в int32[]. Традиционный bitunpack: 1 значение за такт (scalar loop). FastLanes: 16 значений за такт (AVX-512).
Scalar UnpackКлассический bitunpack: цикл по значениям. Для каждого: shift + mask + store. 1 значение / такт. 1M значений @ 3GHz = ~0.33ms. Bottleneck: instruction pipeline latency, branch prediction.
FastLanes SIMDFastLanes: данные переупорядочены в lane layout. Один AVX-512 instruction: load 512 bits → shift + mask → 16 int32 values за один такт. 1M / 16 = 62.5K instructions. ~0.02ms @ 3GHz. 16x ускорение.
Lane LayoutДанные при записи переупорядочиваются: вместо sequential [v0, v1, v2, ...] → interleaved по lanes [v0, v16, v32, ..., v1, v17, v33, ...]. При SIMD load: одна 512-bit load = 16 значений из разных lanes. Shift + mask — одна vectorized операция на все 16.

ARM NEON Support

FastLanes не привязан к x86. Поддержка ARM NEON для Apple Silicon и ARM серверов:

FastLanes: x86 vs ARM
x86 AVX-512512-bit SIMD: 16 × int32 за такт. Серверы: Intel Xeon (Ice Lake+), AMD EPYC (Genoa). Cloud: AWS c7i, GCP C3, Azure Dv5. Максимальная throughput для batch decode.
x86 AVX2256-bit SIMD: 8 × int32 за такт. Более широкая поддержка: все современные x86 CPU. Fallback когда AVX-512 недоступен. 8x vs scalar.
ARM NEON128-bit SIMD: 4 × int32 за такт. Apple M1-M4 (все Mac), AWS Graviton, Ampere Altra. Ниже throughput, но ARM часто компенсирует более высокой тактовой частотой и energy efficiency.

GPU Direct Decode

Vortex спроектирован для GPU-прямого декодирования — данные передаются с storage на GPU минуя CPU:

GPU Decode Path (future)

Traditional: CPU decode

Традиционный GPU pipeline: S3 → CPU memory → CPU decode → CPU → GPU copy → GPU compute. Три copy: S3→CPU, CPU decode (in-place), CPU→GPU. CPU decode — bottleneck для columnar данных.
Pipeline1) S3 → CPU memory (network I/O). 2) CPU decompress + decode (ZSTD + RLE/DICT). 3) CPU → GPU memory copy (PCIe). 4) GPU compute. Bottleneck: step 2 (CPU decode) и step 3 (PCIe copy). GPU idle during steps 1-3.

Vortex: GPU direct decode

Vortex GPU path: S3 → GPU memory (GPUDirect Storage / GDS). GPU decodes Vortex encodings (FastLanes → CUDA kernels). Нет CPU decode, нет CPU→GPU copy. GPU-resident pipeline.
Pipeline1) S3 → GPU memory (GPUDirect Storage, bypass CPU). 2) GPU decode Vortex encodings (FastLanes → CUDA bitunpack, ALP → CUDA multiply). 3) GPU compute on decoded data. Нет CPU bottleneck. GPU utilization: near 100%.
WARNING

GPU direct decode — перспективная архитектура, не production feature текущей версии. NVIDIA GDS (GPUDirect Storage) доступен в CUDA 12+, но Vortex CUDA kernels — в разработке. Ценность: Vortex encodings (FastLanes bit operations) идеально маппятся на GPU SIMT architecture. Parquet encodings (dictionary lookup, RLE state machine) — плохо маппятся на GPU.

TPC-H Benchmarks

Результаты TPC-H SF100 (100GB), сравнение Parquet vs Vortex в DuckDB:

TPC-H SF100: Parquet vs Vortex
Scan ThroughputFull table scan (SELECT * FROM lineitem): Parquet: ~800 MB/s (decode + decompress bound). Vortex: ~8-16 GB/s (SIMD decode, minimal decompress). 10-20x разница для pure scan workloads.
Compression RatioTPC-H lineitem (100GB raw): Parquet+ZSTD: ~30GB (3.3x). Vortex (cascading): ~28-32GB (3.1-3.6x). Comparable compression — Vortex не жертвует compression ради скорости.
Write SpeedWrite lineitem 100GB: Parquet: encode + compress → ~1-2 min. Vortex: encode (FastLanes/ALP/FSST) → ~15-25 sec. 5x faster writes — encoding без heavy compression step (ZSTD).
Random AccessRandom 10K rows from lineitem: Parquet: ~100-200ms (page decode). Vortex: ~5-15ms (mini-block style access через layout tree). 10-20x faster random access (хотя Lance ещё быстрее за счёт sliceable encodings).

Ключевые TPC-H queries:

TPC-H Query Speedups
QueryTPC-H query number и характеристика.
ХарактеристикаОсновной паттерн запроса.
ParquetВремя выполнения с Parquet backend.
VortexВремя выполнения с Vortex backend.
Q1Pricing Summary: scan + filter (l_shipdate <= date) + 4 aggregates. Scan-heavy: читает всю lineitem.
Full scan lineitem (6B rows SF1000) + date filter + GROUP BY + aggregates. CPU-bound on decode + aggregate.
~2.5s: decompress + decode всех колонок → filter → aggregate. Bottleneck: ZSTD decompress step.
~0.3s: compressed compute on date filter (delta-encoded dates → range check on deltas), ALP aggregates на amounts. 8x speedup.
Q6Forecasting Revenue: scan lineitem + 3 range filters + SUM. Highly selective (low result percentage). Classic filter pushdown test.
3 predicates: l_shipdate BETWEEN, l_discount BETWEEN, l_quantity < N. Selective: ~1-2% rows match. SUM(l_extendedprice * l_discount).
~1.8s: scan + decode all filter columns → apply predicates → SUM. Parquet min/max stats skip some row groups.
~0.15s: ALP range check on shipdate (no decompress), ALP range check on discount, bitpacked compare on quantity. Late materialization: decode price only for ~1% matching. 12x speedup.
Q12Shipping Modes: JOIN lineitem + orders, filter on date range + ship mode, GROUP BY + COUNT. Join + aggregation test.
lineitem JOIN orders + date filter + ship_mode IN (...) + GROUP BY. Dictionary on ship_mode, date range filter.
~3.2s: decode both tables → hash join → filter → aggregate. Bottleneck: decode of join columns.
~0.4s: dict lookup ship_mode (no decode), date range on encoded → bitmap → join only matching → aggregate. 8x speedup.

Parquet Compatibility Layer

Vortex обеспечивает обратную совместимость с Parquet через compatibility layer:

Parquet Compatibility: read + write

Read Parquet

Parquet → Vortex: чтение Parquet файлов через Vortex reader. Parquet encodings маппятся на Vortex encodings: DICTIONARY → Dictionary, RLE → RLE, PLAIN → Flat. Можно запустить compressed compute на 'imported' Parquet данных.
MappingParquet DICTIONARY → Vortex Dictionary. Parquet RLE → Vortex RLE. Parquet DELTA_BINARY_PACKED → Vortex Delta + BitPack. Parquet PLAIN → Vortex Flat. Не 1:1, но покрывает основные encodings.

Write Parquet

Vortex → Parquet: конвертация Vortex файлов в Parquet для совместимости с экосистемой (Spark, Presto, Athena). Vortex encodings транслируются в ближайшие Parquet encodings. Потеря: FastLanes, ALP, FSST недоступны в Parquet.
MappingVortex Dictionary → Parquet RLE_DICTIONARY. Vortex Delta → Parquet DELTA_BINARY_PACKED. Vortex ALP → Parquet BYTE_STREAM_SPLIT (closest). Vortex FastLanes → Parquet PLAIN (no equivalent). Lossy: performance advantage lost.

Vortex + Iceberg Integration

Ключевая интеграция: Vortex как data file format в Apache Iceberg tables:

Vortex + Iceberg: 4x ускорение

Iceberg Table (metadata layer)

Apache Iceberg — table format (metadata layer). Data files — pluggable: Parquet, ORC, или... Vortex. Iceberg manifest ссылается на .vortex файлы вместо .parquet. Metadata (snapshots, manifests) — без изменений.
Parquet filesТрадиционный Iceberg: data files = Parquet. Scan: Iceberg metadata → predicate pushdown → Parquet reader (decompress + decode + compute). Bottleneck: Parquet decode pipeline.
Vortex filesVortex-backed Iceberg: data files = .vortex. Scan: Iceberg metadata → predicate pushdown → Vortex reader (compressed compute + late materialization). 4x speedup на типичных OLAP queries.
Преимущества1) Iceberg metadata (snapshots, time travel, schema evolution) — без изменений. 2) Data files — Vortex вместо Parquet. 3) Mixed: старые partitions = Parquet, новые = Vortex. Постепенная миграция. 4) Query engine: DuckDB, Spark (через Vortex reader) понимают .vortex в Iceberg manifest.
NOTE

Vortex + Iceberg — самый практичный путь adoption. Команды не обязаны мигрировать весь data lake: новые партиции пишутся в Vortex, старые остаются в Parquet. Iceberg metadata управляет обоими форматами прозрачно. Это тот же паттерн, который использовал Parquet при вытеснении CSV — постепенная замена, не big-bang миграция.

Lance vs Vortex: позиционирование

Два формата атакуют Parquet с разных сторон:

Lance vs Vortex: разные задачи
АспектКлючевые различия в позиционировании Lance и Vortex.
LanceLance: ML/AI workloads. Random access, vector search, multimodal, versioning.
VortexVortex: аналитические workloads. Compressed compute, fast scans, Parquet replacement.
Primary workloadДля какого типа нагрузки формат оптимизирован.
ML training (random mini-batch), RAG retrieval (vector search), dataset management (versioning, multimodal).
OLAP (scan, filter, aggregate), BI dashboards, data warehouse queries. Прямая замена Parquet.
Key innovationГлавное архитектурное нововведение формата.
100x random access через sliceable encodings. O(1) доступ к строке. Built-in vector search (IVF-PQ, HNSW).
Compressed compute через white-box encodings. Query evaluation без декомпрессии. 10-20x faster scans.
EcosystemОсновные интеграции и способ использования.
Python SDK (lance + lancedb). PyTorch DataLoader. Pandas, Polars, DuckDB через Arrow.
DuckDB core extension. Iceberg integration. Rust API. Нет Python SDK (через DuckDB).
CompressionПодход к сжатию данных.
Container format: protobuf 'any' encodings. Adaptive per-chunk. Mini-block для random access. Forward compat через protobuf.
Cascading encodings: Dict → BitPack → FastLanes. White-box для compressed compute. WASM decoders для forward compat.
Production statusУровень зрелости и production adoption.
LanceDB Cloud: petabyte scale. Lance v2 format stable (Apr 2025). Multimodal GenAI companies in production.
LF incubation. File format stable (v0.36.0). DuckDB core extension (Jan 2026). SpiralDB commercial DB. Production: early adopters.

Итоги

Compressed compute — это не оптимизация, а архитектурный сдвиг:

Compressed Compute: paradigm shift
White-BoxEngine видит структуру encoding'а. Filter на dictionary: O(dict_size). SUM на RLE: Σ(v×c). Нет чёрного ящика декомпрессии. Encoding = API для compute, не просто способ сжатия.
Late MaterializeDecode откладывается до последнего момента. Filter → bitmap → decode только matching. Для 1% selectivity: 100x меньше decode work. Memory footprint: encoded data, не raw values.
SIMD DecodeКогда decode нужен — FastLanes: 16 values per AVX-512 cycle. ARM NEON: 4 values per cycle. GPU future: thousands per cycle. Decode = не bottleneck, а fast path.
Iceberg ReadyDrop-in replacement для Parquet в Iceberg tables. Mixed partitions: old Parquet + new Vortex. 4x query speedup на типичных OLAP workloads. Постепенная миграция без big-bang.

В следующих уроках (Модуль 16) мы продолжим исследование next-gen форматов: Nimble (Meta, “library-as-spec” для Velox) и F3 (CMU, WASM-embedded decoders как SIGMOD 2025 research).

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 4. Vortex-backed таблица: колонка 'status' (RLE-encoded, 5 unique values, sorted). Запрос: SELECT COUNT(*) WHERE status = 'shipped'. Как compressed compute выполняет этот запрос?

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

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

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

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