Skip to content

feat(index): support segmented ngram index#7244

Merged
Xuanwo merged 6 commits into
lance-format:mainfrom
zhangyue19921010:ngram-segmented-index-final
Jul 25, 2026
Merged

feat(index): support segmented ngram index#7244
Xuanwo merged 6 commits into
lance-format:mainfrom
zhangyue19921010:ngram-segmented-index-final

Conversation

@zhangyue19921010

Copy link
Copy Markdown
Contributor

No description provided.

@github-actions github-actions Bot added the A-index Vector index, linalg, tokenizer label Jun 12, 2026
@zhangyue19921010
zhangyue19921010 marked this pull request as draft June 12, 2026 06:49
@github-actions github-actions Bot added the enhancement New feature or request label Jun 12, 2026
@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

@zhangyue19921010
zhangyue19921010 marked this pull request as ready for review June 15, 2026 09:36
@zhangyue19921010
zhangyue19921010 force-pushed the ngram-segmented-index-final branch from 18b23df to 5420a54 Compare June 16, 2026 08:26
@zhangyue19921010

Copy link
Copy Markdown
Contributor Author

Hi @BubbleCal ~ This is a ngram segmented index adoption. Would u have time to take a look? Really appreciate it!

@zhangyue19921010

Copy link
Copy Markdown
Contributor Author

Hi @Xuanwo ~ This is a ngram segmented index adoption. Would u mind to take look? Thanks in advance!

@jackye1995
jackye1995 force-pushed the ngram-segmented-index-final branch from 114669a to f2cfee8 Compare July 23, 2026 12:09
@github-actions github-actions Bot added A-python Python bindings A-java Java bindings + JNI labels Jul 23, 2026
@jackye1995
jackye1995 requested a review from Xuanwo July 23, 2026 12:10
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR adds NGram segmented-index support across Python and Rust, preserves dataset-version and source-field metadata, implements compaction-aware merging and remapping, strengthens index compatibility and CreateIndex conflict handling, and adds end-to-end coverage for overlays, commits, queries, and deferred compaction.

Changes

NGram segmented index lifecycle

Layer / File(s) Summary
Segment provenance and conversion contracts
rust/lance/src/index/api.rs, rust/lance/src/index.rs, python/src/dataset.rs, java/lance-jni/...
IndexSegment preserves dataset-version and source-field metadata, and callers use the shared IntoIndexSegment conversion path.
NGram posting storage and merge engine
rust/lance-index/src/scalar/ngram.rs, rust/lance/src/index/scalar/ngram.rs
NGram postings gain canonical storage metadata, compaction-aware filtering, multi-entry spill streaming, balanced merging, and propagated errors.
Dataset merge, commit, and remap orchestration
rust/lance/src/index/{append.rs,create.rs}, rust/lance/src/index/scalar/ngram.rs, rust/lance/src/dataset/optimize/remapping.rs
NGram builds use segmented commit paths, fragment-reuse-aware merge or rebuild decisions, dataset-version provenance, and deferred-compaction validation.
Index compatibility and transaction conflict handling
rust/lance/src/index.rs, rust/lance/src/io/commit.rs, rust/lance/src/io/commit/conflict_resolver.rs
Index-details compatibility, remapped fragment coverage, CreateIndex rebasing, schema validation, and NGram rewrite conflict checks are expanded.
Python and end-to-end validation
python/python/lance/dataset.py, python/python/tests/test_scalar_index.py, rust/lance/src/dataset/tests/*, rust/lance/src/index/scalar_logical.rs
Python exposes NGram uncommitted segment workflows, and tests cover merging, committing, overlays, remapping, conflict behavior, and query results.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Python
  participant DatasetIndex
  participant NGramMerge
  participant Commit
  participant Query
  Python->>DatasetIndex: create_index_uncommitted
  DatasetIndex->>NGramMerge: merge_existing_index_segments
  NGramMerge-->>DatasetIndex: merged NGram segment and dataset version
  DatasetIndex->>Commit: commit_existing_index_segments
  Commit-->>Python: committed index metadata
  Python->>Query: contains(text, 'needle')
  Query-->>Python: matching row count
Loading

Possibly related PRs

Suggested reviewers: xuanwo, wjones127, jackye1995

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive No description was provided, so there is no meaningful summary to evaluate. Add a brief description of the change and its purpose so reviewers can confirm the scope.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding support for segmented NGram indexes.
Docstring Coverage ✅ Passed Docstring coverage is 85.42% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
rust/lance/src/dataset/optimize/remapping.rs (1)

252-296: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add coverage for legacy remapped-index semantics.

test_ngram_remap_excludes_newer_overlay_fragments exercises the known-coverage branch, including overlay exclusion and dataset_version bumping. Add a parallel legacy path that starts with fragment_bitmap: None, compacts/remaps with an older dataset_version than newer overlays, and asserts that:

  • dataset_version remains at the legacy index baseline, and
  • newer-overlaid fragments are still treated as part of the legacy index coverage/stale mask.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/lance/src/dataset/optimize/remapping.rs` around lines 252 - 296, Add a
parallel legacy-coverage test alongside
test_ngram_remap_excludes_newer_overlay_fragments, initializing the index with
fragment_bitmap: None and an older dataset_version before compaction/remapping
with newer overlays. Assert that the resulting dataset_version remains the
legacy index baseline and that newer-overlaid fragments remain included in the
legacy index coverage/stale mask.
🧹 Nitpick comments (3)
rust/lance/src/index/scalar_logical.rs (1)

1558-1567: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Explain why "compaction_guard" is required for this test to work.

Creating this unrelated, fully-committed NGram index right before compact_files(..., defer_index_remap: true) is what causes the compaction to retain a fragment-reuse mapping at all — without any committed index needing deferred remap, compact_files likely has nothing to defer, so the mapping wouldn't exist and the later merge_existing_index_segments call (which succeeds here) would instead fail like it does in test_ngram_segment_merge_rejects_retired_coverage_without_remap (line 1687-1713 below). This causal link isn't obvious from reading the test and is easy to accidentally break (e.g. if someone removes what looks like a redundant guard index). A short comment would help.

As per coding guidelines, "Add only meaningful comments and tests; comments should explain non-obvious reasoning rather than restating code."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/lance/src/index/scalar_logical.rs` around lines 1558 - 1567, The test’s
committed “compaction_guard” NGram index establishes the fragment-reuse mapping
required by compact_files with defer_index_remap enabled, allowing the later
merge_existing_index_segments call to succeed. Add a concise comment immediately
before dataset.create_index explaining this dependency and warning that removing
the seemingly unrelated index changes the compaction behavior.

Source: Coding guidelines

rust/lance/src/index.rs (1)

1408-1460: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Boolean-flag dispatch across 8 index types is fragile — consider an enum.

merge_existing_index_segments now has 8 all_X flags (vector/inverted/bitmap/btree/fmindex/zonemap/label_list/ngram) feeding both the dispatch if/else chain and the separate dataset_version override list at line 1458. The override list deliberately excludes all_ngram (correctly — ngram::merge_segments already sets the rebuild-aware dataset_version itself, and overriding it here would silently revert a fresh rebuild's version back to the stale min source version), but that correctness is easy to lose the next time an index type is added, since nothing enforces that the override list and the dispatch list stay in sync.

Consider deriving a single SegmentKind enum from index_details once, then using an exhaustive match for both the merge dispatch and the dataset_version handling, so adding a new index type is a compiler-enforced decision rather than an easily-missed list update.

As per coding guidelines: "Use enums instead of magic numbers for format versions, variant types, and discriminators, and rely on exhaustive match."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/lance/src/index.rs` around lines 1408 - 1460, Replace the independent
all_X flags in merge_existing_index_segments with a single SegmentKind derived
from each segment’s index_details, validating that all source segments share the
same kind. Use an exhaustive match on SegmentKind for merge dispatch and
dataset_version handling, preserving ngram’s special behavior by not overriding
its merged version; ensure new index kinds require explicit compiler-enforced
handling.

Source: Coding guidelines

rust/lance-index/src/scalar/ngram.rs (1)

895-901: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use RowAddress instead of raw bitwise fragment extraction.

(row_id >> 32) as u32 manually decodes the fragment id from a row address. The repo convention is to route this through RowAddress so address encoding stays centralized.

♻️ Proposed change
 fn old_filter_keeps(filter: &super::OldIndexDataFilter, row_id: u64) -> bool {
     match filter {
         super::OldIndexDataFilter::Fragments { to_keep, .. } => {
-            to_keep.contains((row_id >> 32) as u32)
+            to_keep.contains(RowAddress::from(row_id).fragment_id())
         }
         super::OldIndexDataFilter::RowIds(valid) => valid.contains(row_id),
     }
 }

Add the import at the top of the file:

use lance_core::utils::address::RowAddress;

As per coding guidelines: "Use RowAddress from lance-core/src/utils/address.rs instead of raw bitwise operations on row addresses."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/lance-index/src/scalar/ngram.rs` around lines 895 - 901, Update
old_filter_keeps to use lance_core::utils::address::RowAddress for fragment
extraction instead of manually shifting row_id, adding the RowAddress import and
preserving the existing to_keep membership check.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@rust/lance/src/dataset/optimize/remapping.rs`:
- Around line 252-296: Add a parallel legacy-coverage test alongside
test_ngram_remap_excludes_newer_overlay_fragments, initializing the index with
fragment_bitmap: None and an older dataset_version before compaction/remapping
with newer overlays. Assert that the resulting dataset_version remains the
legacy index baseline and that newer-overlaid fragments remain included in the
legacy index coverage/stale mask.

---

Nitpick comments:
In `@rust/lance-index/src/scalar/ngram.rs`:
- Around line 895-901: Update old_filter_keeps to use
lance_core::utils::address::RowAddress for fragment extraction instead of
manually shifting row_id, adding the RowAddress import and preserving the
existing to_keep membership check.

In `@rust/lance/src/index.rs`:
- Around line 1408-1460: Replace the independent all_X flags in
merge_existing_index_segments with a single SegmentKind derived from each
segment’s index_details, validating that all source segments share the same
kind. Use an exhaustive match on SegmentKind for merge dispatch and
dataset_version handling, preserving ngram’s special behavior by not overriding
its merged version; ensure new index kinds require explicit compiler-enforced
handling.

In `@rust/lance/src/index/scalar_logical.rs`:
- Around line 1558-1567: The test’s committed “compaction_guard” NGram index
establishes the fragment-reuse mapping required by compact_files with
defer_index_remap enabled, allowing the later merge_existing_index_segments call
to succeed. Add a concise comment immediately before dataset.create_index
explaining this dependency and warning that removing the seemingly unrelated
index changes the compaction behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Pro Plus

Run ID: 8f4356ee-ac64-4714-85a5-610baa6ca13b

📥 Commits

Reviewing files that changed from the base of the PR and between 8f51a21 and f2cfee8.

📒 Files selected for processing (17)
  • java/lance-jni/src/blocking_dataset.rs
  • python/python/lance/dataset.py
  • python/python/tests/test_scalar_index.py
  • python/src/dataset.rs
  • python/src/indices.rs
  • rust/lance-index/src/scalar/ngram.rs
  • rust/lance/src/dataset/index.rs
  • rust/lance/src/dataset/optimize/remapping.rs
  • rust/lance/src/dataset/tests/dataset_overlay_index_masking.rs
  • rust/lance/src/index.rs
  • rust/lance/src/index/api.rs
  • rust/lance/src/index/append.rs
  • rust/lance/src/index/create.rs
  • rust/lance/src/index/scalar.rs
  • rust/lance/src/index/scalar/ngram.rs
  • rust/lance/src/index/scalar_logical.rs
  • rust/lance/src/io/commit/conflict_resolver.rs

@Xuanwo Xuanwo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

commit_existing_index_segments can attach a staged segment to a different column snapshot and silently hide matching rows.

The segment preserves dataset_version, but IntoIndexSegment for IndexMetadata drops the source fields; commit resolves the current column and uses the coordinator's current manifest version as the transaction read_version. If the indexed column is dropped/recreated (the same issue applies to an indexed-field Merge or DataReplacement) after the segment was built and the coordinator has refreshed, those intervening transactions are never checked. The old NGram postings are then advertised as covering the current fragment, so the query has no flat fallback.

On f2cfee815, the public-API reproducer below builds the segment at V1, replaces text at V2/V3, and commits the V1 segment. contains(text, 'dog') returns 3 before the commit and 0 afterward.

Reproducer
use std::sync::Arc;

use arrow_array::{ArrayRef, Int32Array, RecordBatch, RecordBatchIterator, StringArray};
use arrow_schema::{DataType, Field, Schema};
use lance::dataset::NewColumnTransform;
use lance::index::{CreateIndexBuilder, DatasetIndexExt};
use lance::Dataset;
use lance_index::scalar::{BuiltinIndexType, ScalarIndexParams};
use lance_index::IndexType;

#[tokio::main]
async fn main() -> lance::Result<()> {
    let schema = Arc::new(Schema::new(vec![
        Field::new("id", DataType::Int32, false),
        Field::new("text", DataType::Utf8, false),
    ]));
    let batch = RecordBatch::try_new(
        schema.clone(),
        vec![
            Arc::new(Int32Array::from(vec![0, 1, 2])) as ArrayRef,
            Arc::new(StringArray::from(vec!["cat-zero", "cat-one", "cat-two"])) as ArrayRef,
        ],
    )?;
    let reader = RecordBatchIterator::new(vec![Ok(batch)], schema);
    let tmp = tempfile::tempdir()?;
    let mut dataset = Dataset::write(reader, tmp.path().to_str().unwrap(), None).await?;

    let params = ScalarIndexParams::for_builtin(BuiltinIndexType::NGram);
    let segment = CreateIndexBuilder::new(
        &mut dataset,
        &["text"],
        IndexType::NGram,
        &params,
    )
    .name("text_ngram".to_string())
    .fragments(vec![0])
    .execute_uncommitted()
    .await?;
    let source_version = segment.dataset_version;
    let source_field_id = segment.fields[0];

    dataset.drop_columns(&["text"]).await?;
    dataset
        .add_columns(
            NewColumnTransform::SqlExpressions(vec![(
                "text".to_string(),
                "concat('dog-', cast(id as varchar))".to_string(),
            )]),
            Some(vec!["id".to_string()]),
            None,
        )
        .await?;
    let replacement_version = dataset.version().version;
    let replacement_field_id = dataset.schema().field("text").unwrap().id;
    let before_commit = dataset
        .count_rows(Some("contains(text, 'dog')".to_string()))
        .await?;

    dataset
        .commit_existing_index_segments("text_ngram", "text", vec![segment])
        .await?;
    let committed = dataset.load_indices_by_name("text_ngram").await?;
    let after_commit = dataset
        .count_rows(Some("contains(text, 'dog')".to_string()))
        .await?;

    assert_eq!(source_version, 1);
    assert_eq!(replacement_version, 3);
    assert_ne!(source_field_id, replacement_field_id);
    assert_eq!(committed[0].dataset_version, source_version);
    assert_eq!(before_commit, 3);
    assert_eq!(
        after_commit, before_commit,
        "committing an index built for the replaced column must not hide current matches"
    );
    Ok(())
}

The final assertion fails with left: 0, right: 3.

The delayed commit needs to reject or rebuild a segment when its source field/snapshot no longer matches the current indexed data, rather than publishing its old coverage.

@jackye1995
jackye1995 force-pushed the ngram-segmented-index-final branch from f2cfee8 to e75ed76 Compare July 23, 2026 13:34
@jackye1995
jackye1995 requested a review from Xuanwo July 23, 2026 13:34

@coderabbitai coderabbitai 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.

Note

Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.

🟡 Other comments (1)
rust/lance/src/index.rs-1469-1478 (1)

1469-1478: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Stamp FMIndex merges with source-min dataset_version.

fmindex::merge_segments sets dataset_version: dataset.manifest.version, so merged FMIndex segments lose the source staleness provenance that NGram preserves with its explicit source-min. Include all_fmindex in the post-merge override or have FMIndex merge return a source-min dataset_version directly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/lance/src/index.rs` around lines 1469 - 1478, Update the post-merge
dataset version override in the merge flow to include the all_fmindex condition,
ensuring FMIndex merged segments receive source_dataset_version like NGram and
other index types. Alternatively, change fmindex::merge_segments to return the
source-min dataset_version directly, but preserve the existing behavior for all
other index types.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Other comments:
In `@rust/lance/src/index.rs`:
- Around line 1469-1478: Update the post-merge dataset version override in the
merge flow to include the all_fmindex condition, ensuring FMIndex merged
segments receive source_dataset_version like NGram and other index types.
Alternatively, change fmindex::merge_segments to return the source-min
dataset_version directly, but preserve the existing behavior for all other index
types.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Pro Plus

Run ID: 22e5030e-9c60-429e-bad7-27d227235ef5

📥 Commits

Reviewing files that changed from the base of the PR and between f2cfee8 and e75ed76.

📒 Files selected for processing (17)
  • java/lance-jni/src/blocking_dataset.rs
  • python/python/lance/dataset.py
  • python/python/tests/test_scalar_index.py
  • python/src/dataset.rs
  • python/src/indices.rs
  • rust/lance-index/src/scalar/ngram.rs
  • rust/lance/src/dataset/index.rs
  • rust/lance/src/dataset/optimize/remapping.rs
  • rust/lance/src/dataset/tests/dataset_overlay_index_masking.rs
  • rust/lance/src/index.rs
  • rust/lance/src/index/api.rs
  • rust/lance/src/index/append.rs
  • rust/lance/src/index/create.rs
  • rust/lance/src/index/scalar.rs
  • rust/lance/src/index/scalar/ngram.rs
  • rust/lance/src/index/scalar_logical.rs
  • rust/lance/src/io/commit/conflict_resolver.rs

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
rust/lance/src/io/commit/conflict_resolver.rs (1)

40-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the non-obvious semantics of index_build_version.

The dataset_version == 0 sentinel and the max(dataset_version, transaction_read_version) fallback drive segment-source keying and the conflict-filter (< other_version) across the whole CreateIndex rebase path, but the reasoning isn't stated. A short doc comment explaining that 0 means "unversioned/legacy segment → treat as built at the transaction read version" and why the newer of the two versions is chosen would prevent future misuse.

As per coding guidelines: "Add doc comments to magic constants, thresholds, and non-obvious transformation functions, explaining what the value represents and why it was chosen."

📝 Suggested doc comment
+/// Returns the dataset version a staged index segment was built against.
+///
+/// A `dataset_version` of `0` denotes a legacy/unversioned segment, which is
+/// treated as built at the transaction's read version. Otherwise we take the
+/// newer of the segment's recorded version and the read version so segments
+/// staged ahead of the read version are keyed to their true source version.
 fn index_build_version(index: &IndexMetadata, transaction_read_version: u64) -> u64 {
     if index.dataset_version == 0 {
         transaction_read_version
     } else {
         index.dataset_version.max(transaction_read_version)
     }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/lance/src/io/commit/conflict_resolver.rs` around lines 40 - 46, Add a
concise Rust doc comment directly above index_build_version explaining that
dataset_version == 0 represents an unversioned or legacy segment treated as
built at transaction_read_version, and that otherwise the newer of
dataset_version and transaction_read_version is selected for segment-source
keying and conflict filtering.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@rust/lance/src/io/commit/conflict_resolver.rs`:
- Around line 40-46: Add a concise Rust doc comment directly above
index_build_version explaining that dataset_version == 0 represents an
unversioned or legacy segment treated as built at transaction_read_version, and
that otherwise the newer of dataset_version and transaction_read_version is
selected for segment-source keying and conflict filtering.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Pro Plus

Run ID: 4148cdb6-f84d-47b8-85ae-6961c6d50260

📥 Commits

Reviewing files that changed from the base of the PR and between e75ed76 and 5d1b989.

📒 Files selected for processing (8)
  • python/src/indices.rs
  • rust/lance/src/index.rs
  • rust/lance/src/index/api.rs
  • rust/lance/src/index/create.rs
  • rust/lance/src/index/scalar/inverted.rs
  • rust/lance/src/index/scalar_logical.rs
  • rust/lance/src/io/commit.rs
  • rust/lance/src/io/commit/conflict_resolver.rs

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@rust/lance/src/io/commit/conflict_resolver.rs`:
- Around line 2161-2165: Add a regression test in the deferred-rewrite conflict
test suite that rebases an index through a rewrite, invokes finish_create_index
through the normal finish path, and verifies the committed index retains its
original fragment bitmap coverage after remapping. Reuse the existing test setup
and assertions around check_txn, extending coverage through the final commit
rather than stopping at transaction validation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Pro Plus

Run ID: e5d207cd-3abf-4e0e-96df-27fb08798888

📥 Commits

Reviewing files that changed from the base of the PR and between 5d1b989 and 3340acc.

📒 Files selected for processing (1)
  • rust/lance/src/io/commit/conflict_resolver.rs

Comment on lines +2161 to +2165
for index in new_indices.iter_mut() {
if let Some(original) = self.original_index_fragment_bitmaps.get(&index.uuid) {
index.fragment_bitmap = Some(original.clone());
}
}

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.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add a finish-path regression test for bitmap restoration.

The deferred-rewrite tests stop at check_txn; none verifies that finish_create_index restores the original bitmap after conflict-time remapping. Add a test that rebases through a rewrite, calls finish, and asserts the committed index retains its pre-remap coverage.

As per coding guidelines, “Every bugfix and feature must have corresponding tests.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/lance/src/io/commit/conflict_resolver.rs` around lines 2161 - 2165, Add
a regression test in the deferred-rewrite conflict test suite that rebases an
index through a rewrite, invokes finish_create_index through the normal finish
path, and verifies the committed index retains its original fragment bitmap
coverage after remapping. Reuse the existing test setup and assertions around
check_txn, extending coverage through the final commit rather than stopping at
transaction validation.

Source: Coding guidelines

@jackye1995
jackye1995 force-pushed the ngram-segmented-index-final branch from 81877be to f69bbe8 Compare July 24, 2026 21:46

@Xuanwo Xuanwo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thank you!

@Xuanwo
Xuanwo merged commit e08fb7d into lance-format:main Jul 25, 2026
35 checks passed
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 A-java Java bindings + JNI A-python Python bindings enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants