Skip to content

fix(index): keep the trailing rows when shuffling a v2 buffer - #9246

Open
jackylee-ch wants to merge 1 commit into
lance-format:mainfrom
jackylee-ch:fix/ivf-shuffle-tail-rows
Open

jackylee-ch wants to merge 1 commit into
lance-format:mainfrom
jackylee-ch:fix/ivf-shuffle-tail-rows

Conversation

@jackylee-ch

Copy link
Copy Markdown
Contributor

IvfShuffler::total_batches divides a v2 unsorted buffer's row count by SHUFFLE_BATCH_SIZE, so the trailing partial batch is never read; the legacy arm uses the exact reader.num_batches(). A buffer shorter than one batch counts as zero batches and write_partitioned_shuffles returns no files at all, while the caller goes on to commit an index whose fragment bitmap claims full coverage. shuffle_vectors is the only constructor passing is_legacy = false, reached from IndicesBuilder.shuffle_transformed_vectors, so a distributed index build silently loses those vectors.

Round the batch count up, and clamp the row range both readers derive from it -- ReadBatchParams::Range rejects a range past the end of the file.

Testing

cargo test --release -p lance-index --all-features shuffler::test. The new test_v2_shuffle_keeps_every_row covers a partial trailing batch, a buffer shorter than one batch, and an exact multiple; on the old arithmetic the first loses 7 of 2055 rows and the second produces no output. write_unsorted_stream only emits v1 files, so the fixture writes the v2 buffer directly.

@github-actions github-actions Bot added A-index Vector index, linalg, tokenizer bug Something isn't working labels Sep 15, 2026

@lance-gatekeeper lance-gatekeeper Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gate recommendation: approve.

The v2 shuffler now schedules the trailing logical batch and clamps both read passes to the file’s true row count, preserving every transformed vector without changing the legacy path. The regression covers a partial tail, a sub-batch file, and an exact multiple.

@lance-gatekeeper lance-gatekeeper Bot added the K-approved Latest Gatekeeper recommendation permits acceptance. label Sep 15, 2026
`IvfShuffler::total_batches` divides a v2 unsorted buffer's row count by
`SHUFFLE_BATCH_SIZE`, so the trailing partial batch is never read; the legacy arm
of the same function uses the exact `reader.num_batches()`. A buffer shorter than
one batch counts as zero batches and `write_partitioned_shuffles` returns no files
at all, while the caller goes on to commit an index whose fragment bitmap claims
full coverage. `shuffle_vectors` is the only constructor passing
`is_legacy = false`, reached from `IndicesBuilder.shuffle_transformed_vectors`, so
a distributed index build silently loses those vectors.

Round the batch count up, and clamp the row range both readers derive from it --
`ReadBatchParams::Range` rejects a range past the end of the file.

## Testing

`cargo test --release -p lance-index --all-features shuffler::test`. The new
`test_v2_shuffle_keeps_every_row` covers a partial trailing batch, a buffer
shorter than one batch, and an exact multiple; on the old arithmetic the first
loses 7 of 2055 rows and the second produces no output. `write_unsorted_stream`
only emits v1 files, so the fixture writes the v2 buffer directly.
@jackylee-ch
jackylee-ch force-pushed the fix/ivf-shuffle-tail-rows branch from 5430659 to 39c9143 Compare September 15, 2026 12:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-index Vector index, linalg, tokenizer bug Something isn't working K-approved Latest Gatekeeper recommendation permits acceptance.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant