Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f2061fd
feat: optimize IVF index build reads
jerry-024 Sep 9, 2026
3bc5ad5
perf(vindex): complete IVF build read optimization
jerry-024 Sep 10, 2026
fad54e3
fix(vindex): stratify IVF training sampling
jerry-024 Sep 10, 2026
0ffc393
fix(vindex): preserve IVF sampling quality
jerry-024 Sep 10, 2026
af2bcd3
fix(vindex): harden sparse build pipeline
jerry-024 Sep 10, 2026
999a530
perf(vindex): parallelize sparse parquet reads
jerry-024 Sep 11, 2026
17db1f8
perf(parquet): budget sparse reads by selected pages
jerry-024 Sep 11, 2026
e7bb7b7
fix(vindex): guard sparse training reads
jerry-024 Sep 11, 2026
000a1c1
fix(vindex): require meaningful sparse savings and cover safety regre…
jerry-024 Sep 14, 2026
8325dc9
refactor(vindex): keep sparse build changes focused
jerry-024 Sep 14, 2026
c866b82
fix(vindex): scope sparse savings to current shard
jerry-024 Sep 14, 2026
8ec4e02
feat(vindex): build IVF indexes with granule pipeline
jerry-024 Sep 17, 2026
43022ec
fix(vindex): simplify granule build pipeline
jerry-024 Sep 17, 2026
07758fb
test(vindex): use search result row ids
jerry-024 Sep 17, 2026
799df50
fix: handle overlapping vindex granule providers
jerry-024 Sep 17, 2026
5fd19b7
fix: report granule spill metrics
jerry-024 Sep 17, 2026
fc46acc
feat(vindex): add granule build toggle
jerry-024 Sep 18, 2026
407e396
fix(vindex): jitter granule training samples
jerry-024 Sep 20, 2026
1a12958
fix(vindex): adapt granule reads to read budget API
jerry-024 Sep 20, 2026
a2ab2f8
fix(vindex): report actual trainer sample counts
jerry-024 Sep 20, 2026
2125a30
fix(vindex): sample granule training in logical row space
jerry-024 Sep 20, 2026
de03ff2
refactor(vindex): remove redundant granule planning work
jerry-024 Sep 20, 2026
ae42c75
Merge upstream/main and resolve PR 800 test conflicts
jerry-024 Sep 20, 2026
d1f86cd
fix(vindex): honor Parquet page index option in granule planning
jerry-024 Sep 20, 2026
8af080f
fix(vindex): isolate channel workers from blocking pool
jerry-024 Sep 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
545 changes: 517 additions & 28 deletions crates/paimon/src/arrow/format/parquet.rs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions crates/paimon/src/table/vindex_index_build_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
// under the License.

mod extraction;
mod pipeline;
mod planning;
mod timing;
mod validation;
Expand Down
108 changes: 89 additions & 19 deletions crates/paimon/src/table/vindex_index_build_builder/extraction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,31 +23,114 @@ use crate::{Error, Result};
use arrow_array::{Array, FixedSizeListArray, Float32Array, Int64Array, ListArray, RecordBatch};

pub(super) fn data_split_for_shard(shard: &VindexIndexShard) -> Result<DataSplit> {
data_split_for_shard_ranges(
shard,
vec![RowRange::new(shard.row_range_start, shard.row_range_end)],
)
}

pub(super) fn data_split_for_shard_ranges(
shard: &VindexIndexShard,
row_ranges: Vec<RowRange>,
) -> Result<DataSplit> {
DataSplitBuilder::new()
.with_snapshot(shard.snapshot_id)
.with_partition(shard.partition.clone())
.with_bucket(shard.source_bucket)
.with_bucket_path(shard.bucket_path.clone())
.with_total_buckets(shard.total_buckets)
.with_data_files(shard.files.clone())
.with_row_ranges(vec![RowRange::new(
shard.row_range_start,
shard.row_range_end,
)])
.with_row_ranges(row_ranges)
.build()
}

pub(super) struct ValidatedVectorBatch<'a> {
pub(super) values: &'a [f32],
pub(super) bytes: &'a [u8],
pub(super) row_ids: &'a [i64],
pub(super) row_count: usize,
}

pub(super) fn extract_vector_batch<'a>(
batch: &'a RecordBatch,
index_column: &str,
dimension: usize,
) -> Result<ValidatedVectorBatch<'a>> {
validate_vector_batch_with(batch, index_column, dimension, |_| Ok(()))
}

pub(super) fn validate_vector_batch<'a>(
batch: &'a RecordBatch,
index_column: &str,
dimension: usize,
expected_row_id: &mut i64,
) -> Result<ValidatedVectorBatch<'a>> {
validate_vector_batch_with(batch, index_column, dimension, |row_id| {
if row_id != *expected_row_id {
return Err(Error::DataInvalid {
message: format!(
"vindex vector extraction expected _ROW_ID {}, got {}",
expected_row_id, row_id
),
source: None,
});
}
*expected_row_id = expected_row_id
.checked_add(1)
.ok_or_else(|| Error::DataInvalid {
message: "vindex expected row id overflows i64".to_string(),
source: None,
})?;
Ok(())
})
}

pub(super) fn validate_vector_batch_ranges<'a>(
batch: &'a RecordBatch,
index_column: &str,
dimension: usize,
ranges: &[RowRange],
range_index: &mut usize,
expected_row_id: &mut i64,
) -> Result<ValidatedVectorBatch<'a>> {
validate_vector_batch_with(batch, index_column, dimension, |row_id| {
let range = ranges.get(*range_index).ok_or_else(|| Error::DataInvalid {
message: format!("vindex vector extraction got unexpected _ROW_ID {row_id}"),
source: None,
})?;
if row_id != *expected_row_id {
return Err(Error::DataInvalid {
message: format!(
"vindex vector extraction expected _ROW_ID {}, got {}",
expected_row_id, row_id
),
source: None,
});
}
if row_id == range.to() {
*range_index += 1;
*expected_row_id = match ranges.get(*range_index) {
Some(next) => next.from(),
None => row_id.checked_add(1).ok_or_else(|| Error::DataInvalid {
message: "vindex expected row id overflows i64".to_string(),
source: None,
})?,
};
} else {
*expected_row_id = row_id.checked_add(1).ok_or_else(|| Error::DataInvalid {
message: "vindex expected row id overflows i64".to_string(),
source: None,
})?;
}
Ok(())
})
}

fn validate_vector_batch_with<'a>(
batch: &'a RecordBatch,
index_column: &str,
dimension: usize,
mut validate_row_id: impl FnMut(i64) -> Result<()>,
) -> Result<ValidatedVectorBatch<'a>> {
let vector_index = batch
.schema()
Expand Down Expand Up @@ -163,28 +246,15 @@ pub(super) fn validate_vector_batch<'a>(
});
}
for row_id in row_ids.values() {
if *row_id != *expected_row_id {
return Err(Error::DataInvalid {
message: format!(
"vindex vector extraction expected _ROW_ID {}, got {}",
expected_row_id, row_id
),
source: None,
});
}
*expected_row_id = expected_row_id
.checked_add(1)
.ok_or_else(|| Error::DataInvalid {
message: "vindex expected row id overflows i64".to_string(),
source: None,
})?;
validate_row_id(*row_id)?;
}

let byte_start = checked_vector_bytes(start, 1)?;
let byte_end = checked_vector_bytes(end, 1)?;
Ok(ValidatedVectorBatch {
values: &values.values()[start..end],
bytes: &values.values().inner().as_slice()[byte_start..byte_end],
row_ids: row_ids.values(),
row_count: batch.num_rows(),
})
}
Loading
Loading