Skip to content

perf(vindex): parallelize Parquet reads and multipart index uploads - #736

Draft
jerry-024 wants to merge 17 commits into
apache:mainfrom
jerry-024:perf/ivfpq-build-performance
Draft

perf(vindex): parallelize Parquet reads and multipart index uploads#736
jerry-024 wants to merge 17 commits into
apache:mainfrom
jerry-024:perf/ivfpq-build-performance

Conversation

@jerry-024

@jerry-024 jerry-024 commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Purpose

Speed up vector-index builds by removing two object-storage bottlenecks:

  1. full-file scans were unnecessarily excluded from parallel Parquet row-group reads;
  2. serialized indexes uploaded multipart chunks one at a time.

Changes

  • Treat full-coverage row_ranges without a deletion vector as an unfiltered scan, allowing the existing parallel row-group path to run. Partial ranges, deletion vectors, and empty ranges keep their previous semantics.
  • Keep oversized row groups charged against the full configured Parquet read budget, preserving max_inflight_bytes as a strict projected-byte admission limit, and warn once when a row group exceeds it.
  • Upload vector-index multipart chunks with four parts in flight. Other writers retain their existing serial behavior.
  • Add opt-in aggregate diagnostics for vector-index build phases and Parquet row-group reads.
  • Add a production-path IVF-PQ build benchmark example.

Reproduce the IVF-PQ build benchmark

The benchmark is in ivfpq_build_benchmark.rs. It builds an IVF-PQ index with dimension 768, cosine distance, nlist=4096, and pq.m=192 on an existing Paimon table:

PAIMON_CATALOG_OPTIONS='<catalog-options-json>' \
PAIMON_LOG_VECTOR_INDEX_BUILD_TIMING=1 \
cargo run --release -p paimon --example ivfpq_build_benchmark -- \
  <database> <table> <vector-column> --drop-existing

Benchmark

Cohere 10M × 768 dimensions, cosine IVF-PQ (nlist=4096, pq.m=192, 8 bits), 10 Parquet files / 100 row groups, direct OSS, and no local cache.

Parallel Parquet reads

Both baseline and this PR use an explicit 512 MiB Parquet read budget, so the comparison isolates the changes in this PR while retaining strict byte accounting.

metric baseline this PR change
end-to-end build, 3-run median 546.153s 527.113s −3.49%
source batch wait 105.346s 59.361s −43.65%
peak in-flight row groups 1 2 +1
peak RSS 4.24 GiB 4.37 GiB +137 MB

The 512 MiB budget is a workload-specific benchmark setting and must be configured explicitly. The default remains 256 MiB.

Concurrent multipart upload

With all other benchmark inputs held constant, four in-flight multipart uploads reduced the serialize/upload phase from 30.3s to 4.6s (−84.8%). The vector-index writer alone uses this concurrency; other writers keep their existing behavior.

Tests

  • Full, stitched, partial, empty, and deletion-vector row selections, including _ROW_ID parity.
  • Shared Parquet budget accounting and peak in-flight diagnostics.
  • Oversized row groups consume the full budget and emit a one-time warning; ordinary and tiny row-group accounting remains strict.
  • Vector-index build timing aggregation and existing builder tests.

API and format

No public API or file/index format changes. The concurrent writer helper is crate-private.

jerry-024 and others added 8 commits August 18, 2026 15:57
The default_training_vector_count call was only used to populate a
timing log field, but it ran unconditionally and propagated errors,
introducing a new build failure path even when timing diagnostics
were disabled. Compute it only when timing is enabled and fall back
to 0 on error instead of failing the build.

Co-Authored-By: Claude <noreply@anthropic.com>
The vector index (~2 GB) is serialized as a sequential stream into an
opendal writer that uploads its 8 MiB multipart chunks strictly one at a
time -- ~244 serial round trips per index on object storage. Add
async_writer_with_concurrency and let the index upload keep 4 parts in
flight (32 MiB buffer), overlapping serialization with uploads. Parquet
and other async_writer users keep the previous serial behavior.
@jerry-024
jerry-024 marked this pull request as draft August 21, 2026 02:18
* main:
  perf: vectorize raw vector search (apache#734)
  feat(file_index): add predicate evaluation foundation (apache#721)
  feat(go): add postpone fixed-bucket write bindings (apache#722)
  perf(vindex): split build timing logs by phase (apache#723)
  fix(avro): read TIME, BLOB, MULTISET and non-string-key map columns (apache#724)
  fix(datafusion): surface tag create-time and retention in $tags (apache#728)
  [core] Support multivalue global index (apache#731)
  feat: add Java-compatible array predicate pushdown (apache#732)
  fix: serialize unbounded varchar as string (apache#730)
  perf(vindex): decouple vector read threads and remove chunk barrier (apache#720)
  feat(vindex): add DiskANN and IVF-SQ/RQ support (apache#726)

# Conflicts:
#	crates/paimon/src/table/data_file_reader.rs
#	crates/paimon/src/table/vindex_index_build_builder.rs
@jerry-024 jerry-024 changed the title perf(vindex): add detailed build timing logs perf: parallel row-group reads and concurrent index upload for vector-index builds Aug 21, 2026
A row group whose projected bytes exceed the whole read budget previously
clamped to every byte permit, so one oversized row group serialized the
scan: wide vector columns project ~294 MiB per row group against the
256 MiB default budget, and parallel row-group reads silently degraded
to 1 in flight unless the user hand-tuned max-inflight-bytes.

Cap a single acquisition at budget / min(parallelism, 4) instead. Row
groups at or below their fair share keep exact accounting (no behavior
change for ordinary layouts); oversized row groups admit up to four
concurrent reads, matching what the 768 MiB hand-tuned budget achieved
(source wait -43.7% on a 10M-row 768-dim build) without configuration.

The byte budget thereby becomes a fair-admission mechanism for large
row groups rather than a strict projected-byte ceiling; the share
divisor is capped at 4 until wider RSS measurements justify more.
@jerry-024 jerry-024 changed the title perf: parallel row-group reads and concurrent index upload for vector-index builds perf(vindex): parallelize Parquet reads and multipart index uploads Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant