Skip to content

feat(scanner): add external row-address mask prefilter - #7288

Merged
Xuanwo merged 4 commits into
lance-format:mainfrom
JulianYG:feat/row-addr-mask-prefilter
Aug 23, 2026
Merged

feat(scanner): add external row-address mask prefilter#7288
Xuanwo merged 4 commits into
lance-format:mainfrom
JulianYG:feat/row-addr-mask-prefilter

Conversation

@JulianYG

@JulianYG JulianYG commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Addresses #6852.

What

Adds Scanner::with_row_addr_prefilter(RowAddrMask), letting callers pass a
precomputed row-address allow/block mask as a prefilter into vector and plain
scans, reusing the scanner's existing retrieval plan rather than re-deriving it.

Motivation

Some pipelines precompute a set of eligible rows out-of-band (e.g. a stored
bitmap of rows belonging to a logical subset / dataset) and want to run KNN or a
plain scan restricted to that set -- without expressing it as a SQL filter. A
multi-hundred-thousand-element IN (...) is impractical to build and parse;
passing the row set directly is far cheaper.

How

The mask threads into the existing prefilter machinery at three points:

  • ANN branch: fed through PreFilterSource into new_knn_exec, ANDed with
    any deletion/SQL prefilter via a MaskAndLoader.
  • Flat / unindexed-fragment branch: a new RowAddrMaskFilterExec filters
    scan output by _rowid, so rows appended after the index build are honored.
  • Plain (non-vector) scan: the mask is supplied as the FilteredReadExec
    index input, so only masked rows are read; a SQL filter becomes a refine on top.

Deletions are still applied by DatasetPreFilter; illegal addresses are ignored.

Status

Draft, pending API agreement on #6852. Behavior is exercised by an out-of-tree
PyO3 binding's test suite (based on v7.0.0, this PR is rebased); cargo check -p lance and cargo fmt are clean. I'd
appreciate guidance on the public API shape before finalizing in-tree tests.

@github-actions github-actions Bot added the enhancement New feature or request label Jun 16, 2026
@JulianYG
JulianYG marked this pull request as draft June 16, 2026 07:54
@JulianYG
JulianYG force-pushed the feat/row-addr-mask-prefilter branch from 19a9518 to ed88757 Compare July 10, 2026 04:15
@coderabbitai

coderabbitai Bot commented Jul 10, 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

Changes

The scanner accepts an optional RowAddrMask and applies it to filtered reads, flat scans, appended fragments, ANN/KNN execution, and FTS queries. New execution support intersects prefilters and filters batches by _rowid. Tests cover masking, limits, legacy storage, ANN, and FTS behavior.

Row-address prefilter

Layer / File(s) Summary
Mask execution primitives
rust/lance/src/io/exec/row_addr_mask.rs, rust/lance/src/io/exec.rs, rust/lance/src/io/exec/utils.rs
Adds mask intersection, _rowid batch filtering, validation, tests, and execution-node exports.
Scanner filtered-read integration
rust/lance/src/dataset/scanner.rs, rust/lance/src/io/exec/filtered_read.rs
Adds the scanner builder and applies mask-derived inputs, refine-only filters, projection handling, limit behavior, and legacy-storage validation.
ANN and flat vector-search masking
rust/lance/src/io/exec/knn.rs, rust/lance/src/dataset/scanner.rs
Propagates the mask through ANN execution and filters flat or appended vector-search branches.
FTS mask propagation and validation
rust/lance/src/io/exec/fts.rs, rust/lance/src/dataset/scanner.rs
Passes masks into phrase and match prefilters and filters flat FTS results before top-k selection; adds end-to-end coverage.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested labels: A-index

Suggested reviewers: westonpace, xuanwo, bubblecal

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly names the scanner and external row-address mask prefilter, matching the main change.
Description check ✅ Passed The description accurately explains the new row-address mask prefilter across plain, ANN, and FTS scans.
Docstring Coverage ✅ Passed Docstring coverage is 94.12% 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

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

@JulianYG
JulianYG marked this pull request as ready for review July 11, 2026 08:37
@JulianYG

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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: 5

🤖 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/dataset/scanner.rs`:
- Around line 737-741: The external_row_mask field and its ANN execution
plumbing should use Arc<RowAddrMask> instead of cloning RowAddrMask values.
Update new_knn_exec, ANNIvfSubIndexExec construction and with_new_children, plus
ann, multivec_ann, knn_combined, and flat-scan paths, to clone the Arc cheaply
while preserving mask behavior. Revise the field documentation to mention both
vector-search prefiltering and use as the plain-scan row source via
use_external_mask.
- Around line 1205-1214: The documentation for with_row_addr_prefilter must
match new_filtered_read: describe the mask as applying to both vector-search and
plain scans as implemented, rather than claiming it only affects nearest
queries. Reword “ANDed” using clear wording such as “combined with” to satisfy
the typos check, while preserving the existing row-address and branch semantics.
- Around line 1211-1214: Reject configurations using with_row_addr_prefilter
when the dataset manifest uses stable row IDs. Add an early invalid-input or
not-supported validation in validate_options or create_plan, before applying
external_row_mask, while preserving the existing behavior for datasets without
stable row IDs.

In `@rust/lance/src/io/exec/knn.rs`:
- Line 1393: Reword the documentation comment for the external row-address
allow/block mask to replace “ANDed” with a spell-check-safe equivalent, while
preserving that the mask is combined with the prefilter using logical AND.

In `@rust/lance/src/io/exec/row_addr_mask.rs`:
- Line 10: Replace the flagged “ANDed” wording in the row address mask
documentation and the corresponding occurrences in knn.rs and scanner.rs with
typos-safe terminology, preserving the description of deletion vectors being
combined by DatasetPreFilter. Alternatively, add an appropriate allow-entry to
the typos configuration if retaining the terminology is required.
🪄 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: ASSERTIVE

Plan: Pro Plus

Run ID: 1f78fb0f-93fb-46cb-bcb6-510b6431ea01

📥 Commits

Reviewing files that changed from the base of the PR and between 1946a5a and ed88757.

📒 Files selected for processing (4)
  • rust/lance/src/dataset/scanner.rs
  • rust/lance/src/io/exec.rs
  • rust/lance/src/io/exec/knn.rs
  • rust/lance/src/io/exec/row_addr_mask.rs

Comment thread rust/lance/src/dataset/scanner.rs Outdated
Comment thread rust/lance/src/dataset/scanner.rs Outdated
Comment on lines +1211 to +1214
pub fn with_row_addr_prefilter(&mut self, mask: RowAddrMask) -> &mut Self {
self.external_row_mask = Some(mask);
self
}

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm stable-row-id detection API and that no guard exists for external_row_mask
rg -nP 'uses_stable_row_ids' rust/lance/src/dataset/scanner.rs rust/lance/src/dataset/*.rs
rg -nP 'external_row_mask' rust/lance/src/dataset/scanner.rs

Repository: lance-format/lance

Length of output: 2501


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the scanner code around the external row mask, validation, and mask application paths.
sed -n '700,780p' rust/lance/src/dataset/scanner.rs
printf '\n---\n'
sed -n '1188,1235p' rust/lance/src/dataset/scanner.rs
printf '\n---\n'
sed -n '2888,2995p' rust/lance/src/dataset/scanner.rs
printf '\n---\n'
sed -n '3908,4110p' rust/lance/src/dataset/scanner.rs
printf '\n---\n'
sed -n '4728,4825p' rust/lance/src/dataset/scanner.rs
printf '\n---\n'
sed -n '2488,2535p' rust/lance/src/dataset/scanner.rs

Repository: lance-format/lance

Length of output: 23512


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check whether scanner validation already rejects external_row_mask for stable-row-id datasets.
rg -nC 3 'validate_options|create_plan|external_row_mask|uses_stable_row_ids' rust/lance/src/dataset/scanner.rs

Repository: lance-format/lance

Length of output: 13474


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the row-address mask types and the exec path that consumes them.
rg -nC 4 'struct RowAddrMask|enum RowAddrMask|RowAddrMaskFilterExec|mask_as_index_input|RowAddr' rust/lance/src

Repository: lance-format/lance

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Narrowly inspect the RowAddrMask-related execution path to see what column it filters and
# whether scanner-specific validation already rejects stable-row-id datasets.
rg -nC 3 'RowAddrMaskFilterExec|mask_as_index_input|with_row_addr_prefilter|uses_stable_row_ids\(\)' rust/lance/src/dataset/scanner.rs rust/lance/src/index/prefilter.rs rust/lance/src -g '!**/target/**' | head -n 220

Repository: lance-format/lance

Length of output: 17644


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the RowAddrMask-related execution path to see what column it filters and
# whether scanner-specific validation already rejects stable-row-id datasets.
sed -n '1,260p' rust/lance/src/index/prefilter.rs
printf '\n---\n'
sed -n '2388,2538p' rust/lance/src/dataset/scanner.rs
printf '\n---\n'
rg -nC 2 'RowAddrMaskFilterExec|mask_as_index_input|with_row_addr_prefilter' rust/lance/src -g '!**/target/**'

Repository: lance-format/lance

Length of output: 24350


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the row-address mask execution semantics to see whether it always interprets
# the input as physical row addresses or can also operate on stable row ids.
sed -n '1,220p' rust/lance/src/io/exec/row_addr_mask.rs

Repository: lance-format/lance

Length of output: 5564


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' rust/lance/src/io/exec/row_addr_mask.rs

Repository: lance-format/lance

Length of output: 5564


Reject with_row_addr_prefilter on stable-row-id datasets. This path reads _rowid, which only matches physical row addresses when stable row ids are disabled. On manifest.uses_stable_row_ids() datasets it can silently filter the wrong rows, so add an early invalid_input/not_supported check in validate_options or create_plan.

🤖 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/scanner.rs` around lines 1211 - 1214, Reject
configurations using with_row_addr_prefilter when the dataset manifest uses
stable row IDs. Add an early invalid-input or not-supported validation in
validate_options or create_plan, before applying external_row_mask, while
preserving the existing behavior for datasets without stable row IDs.

Source: Coding guidelines

Comment thread rust/lance/src/io/exec/knn.rs Outdated
Comment thread rust/lance/src/io/exec/row_addr_mask.rs Outdated
@JulianYG
JulianYG force-pushed the feat/row-addr-mask-prefilter branch from ed88757 to 7c82510 Compare July 19, 2026 12:06
@JulianYG

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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/scanner.rs (1)

2927-3008: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Critical: external_row_mask is silently ignored on plain scans for legacy-storage datasets.

filtered_read (lines 3013-3050) dispatches to legacy_filtered_read when self.dataset.is_legacy_storage() is true, and legacy_filtered_read has no awareness of external_row_mask at all — it never builds an index_input from the mask and nothing wraps its output afterward. Contrast this with the vector-search paths (vector_search's flat fallback and knn_combined), which explicitly re-wrap their scan output with RowAddrMaskFilterExec regardless of which internal path executed. For the plain-scan path (create_planfiltered_read_sourcefiltered_read), there is no such fallback wrap — masking is enforced only through new_filtered_read's use_external_mask/mask_as_index_input mechanism.

The net effect: on a legacy-storage-format dataset, calling Scanner::with_row_addr_prefilter(mask) followed by a plain (non-nearest) scan will return unmasked results, silently contradicting the updated doc ("On a plain scan the mask is used directly as the row source.").

🐛 Proposed minimal safeguard (reject the unsupported combination)
     fn validate_options(&self) -> Result<()> {
         if self.batch_readahead == 0 {
             return Err(Error::invalid_input_source(
                 "batch_readahead must be greater than 0, got 0".into(),
             ));
         }
+
+        if self.external_row_mask.is_some()
+            && self.nearest.is_none()
+            && self.dataset.is_legacy_storage()
+        {
+            return Err(Error::not_supported(
+                "with_row_addr_prefilter is not supported for plain scans on datasets using the legacy storage format".to_string(),
+            ));
+        }

A more complete fix would be to implement mask support inside legacy_filtered_read (or to wrap filtered_read_source's output with RowAddrMaskFilterExec unconditionally, mirroring the vector-search paths) instead of just rejecting the combination.

🤖 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/scanner.rs` around lines 2927 - 3008, Prevent plain
scans from silently ignoring external_row_mask on legacy-storage datasets. In
filtered_read, detect the combination of self.dataset.is_legacy_storage() and
self.external_row_mask and return an explicit unsupported-operation error before
dispatching to legacy_filtered_read. Preserve existing behavior for legacy scans
without a mask and non-legacy masked scans through new_filtered_read.
🧹 Nitpick comments (2)
rust/lance/src/dataset/scanner.rs (2)

1210-1226: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing test coverage for the new external row-address mask feature.

This PR stack introduces a significant, correctness-sensitive feature (external RowAddrMask prefiltering) spanning three files, but no tests are visible in the diff for any layer: the core filtering primitives, the KNN mask-propagation wiring, or the public Scanner::with_row_addr_prefilter API and its downstream effects (plain scan, ANN, flat/appended-fragment vector search). Per coding guidelines, every feature should have corresponding tests.

  • rust/lance/src/dataset/scanner.rs#L1210-L1226: add tests exercising Scanner::with_row_addr_prefilter end-to-end for (a) a plain scan, (b) an indexed vector search, (c) a flat/unindexed vector search, and (d) appended-fragment vector search (knn_combined), verifying only masked rows are returned in each case.
  • rust/lance/src/io/exec/row_addr_mask.rs#L33-L156: add unit tests for apply_mask (null _rowid handling, allow/block selection) and MaskAndLoader::load (intersection with and without an inner loader).
  • rust/lance/src/io/exec/knn.rs#L1104-L1981: add a test verifying ANNIvfSubIndexExec::execute correctly intersects external_mask with an existing filter-derived prefilter loader (not just the no-prefilter case).
🤖 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/scanner.rs` around lines 1210 - 1226, Add
comprehensive tests for external RowAddrMask filtering: in
rust/lance/src/dataset/scanner.rs lines 1210-1226, cover
Scanner::with_row_addr_prefilter for plain scans, indexed vector searches,
flat/unindexed searches, and appended-fragment knn_combined searches, verifying
only masked rows return; in rust/lance/src/io/exec/row_addr_mask.rs lines
33-156, test apply_mask null _rowid handling and allow/block selection plus
MaskAndLoader::load with and without an inner loader; in
rust/lance/src/io/exec/knn.rs lines 1104-1981, test ANNIvfSubIndexExec::execute
intersects external_mask with an existing filter-derived prefilter loader.

Source: Coding guidelines


3052-3076: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate serialize/stream/OneShotExec boilerplate between mask_as_index_input and u64s_as_take_input.

Both functions build an IndexExprResult, compute fragments_covered/format, serialize into a batch, and wrap it in a OneShotExec via RecordBatchStreamAdapter — identical tail logic duplicated verbatim. Extracting a shared helper (e.g. fn index_result_as_index_input(&self, index_result: IndexExprResult) -> Result<Arc<dyn ExecutionPlan>>) would remove the duplication and reduce the risk of the two implementations diverging over time.

♻️ Proposed refactor
+    fn index_result_as_index_input(
+        &self,
+        index_result: IndexExprResult,
+    ) -> Result<Arc<dyn ExecutionPlan>> {
+        let fragments_covered = self.dataset.fragment_bitmap.as_ref().clone();
+        let format = self.index_expr_result_format();
+        let batch = index_result.serialize(&fragments_covered, format)?;
+        let schema = batch.schema();
+        let stream = futures::stream::once(async move { Ok(batch) });
+        let stream = Box::pin(RecordBatchStreamAdapter::new(schema, stream));
+        Ok(Arc::new(OneShotExec::new(stream)))
+    }
+
     fn mask_as_index_input(&self, mask: &RowAddrMask) -> Result<Arc<dyn ExecutionPlan>> {
-        let index_result = IndexExprResult::exact(mask.clone());
-        let fragments_covered = self.dataset.fragment_bitmap.as_ref().clone();
-        let format = self.index_expr_result_format();
-        let batch = index_result.serialize(&fragments_covered, format)?;
-        let schema = batch.schema();
-        let stream = futures::stream::once(async move { Ok(batch) });
-        let stream = Box::pin(RecordBatchStreamAdapter::new(schema, stream));
-        Ok(Arc::new(OneShotExec::new(stream)))
+        self.index_result_as_index_input(IndexExprResult::exact(mask.clone()))
     }

     fn u64s_as_take_input(&self, u64s: Vec<u64>) -> Result<Arc<dyn ExecutionPlan>> {
         let row_addrs = RowAddrTreeMap::from_iter(u64s);
         let row_addr_mask = RowAddrMask::from_allowed(row_addrs);
-        let index_result = IndexExprResult::exact(row_addr_mask);
-        let fragments_covered = self.dataset.fragment_bitmap.as_ref().clone();
-        let format = self.index_expr_result_format();
-        let batch = index_result.serialize(&fragments_covered, format)?;
-        let schema = batch.schema();
-        let stream = futures::stream::once(async move { Ok(batch) });
-        let stream = Box::pin(RecordBatchStreamAdapter::new(schema, stream));
-        Ok(Arc::new(OneShotExec::new(stream)))
+        self.index_result_as_index_input(IndexExprResult::exact(row_addr_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/scanner.rs` around lines 3052 - 3076, Extract the
shared serialization and execution-plan construction from mask_as_index_input
and u64s_as_take_input into a helper such as index_result_as_index_input,
accepting an IndexExprResult and returning the OneShotExec plan. Update both
callers to build their respective IndexExprResult and delegate to the helper,
preserving existing behavior.
🤖 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/scanner.rs`:
- Around line 2927-3008: Prevent plain scans from silently ignoring
external_row_mask on legacy-storage datasets. In filtered_read, detect the
combination of self.dataset.is_legacy_storage() and self.external_row_mask and
return an explicit unsupported-operation error before dispatching to
legacy_filtered_read. Preserve existing behavior for legacy scans without a mask
and non-legacy masked scans through new_filtered_read.

---

Nitpick comments:
In `@rust/lance/src/dataset/scanner.rs`:
- Around line 1210-1226: Add comprehensive tests for external RowAddrMask
filtering: in rust/lance/src/dataset/scanner.rs lines 1210-1226, cover
Scanner::with_row_addr_prefilter for plain scans, indexed vector searches,
flat/unindexed searches, and appended-fragment knn_combined searches, verifying
only masked rows return; in rust/lance/src/io/exec/row_addr_mask.rs lines
33-156, test apply_mask null _rowid handling and allow/block selection plus
MaskAndLoader::load with and without an inner loader; in
rust/lance/src/io/exec/knn.rs lines 1104-1981, test ANNIvfSubIndexExec::execute
intersects external_mask with an existing filter-derived prefilter loader.
- Around line 3052-3076: Extract the shared serialization and execution-plan
construction from mask_as_index_input and u64s_as_take_input into a helper such
as index_result_as_index_input, accepting an IndexExprResult and returning the
OneShotExec plan. Update both callers to build their respective IndexExprResult
and delegate to the helper, preserving existing behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Pro Plus

Run ID: 774a77ab-63af-4315-b074-31a60d5f31e5

📥 Commits

Reviewing files that changed from the base of the PR and between ed88757 and 7c82510.

📒 Files selected for processing (4)
  • rust/lance/src/dataset/scanner.rs
  • rust/lance/src/io/exec.rs
  • rust/lance/src/io/exec/knn.rs
  • rust/lance/src/io/exec/row_addr_mask.rs

@JulianYG

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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: 2

Caution

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

⚠️ Outside diff range comments (3)
rust/lance/src/dataset/scanner.rs (2)

1210-1222: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add a compiling rustdoc example and API links.

with_row_addr_prefilter is a new public API, but its documentation has no example or links to RowAddrMask, RowAddrTreeMap, or the relevant scan methods. Add a synchronized no_run example using the actual signature.

🤖 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/scanner.rs` around lines 1210 - 1222, Update the
rustdoc for with_row_addr_prefilter to include a compiling no_run example using
its actual signature, and add API links for RowAddrMask, RowAddrTreeMap, and the
relevant scanner methods. Keep the example synchronized with the current public
API and existing documentation behavior.

Source: Coding guidelines


3975-3979: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Add Scanner-level regression tests for the new mask contract.

The supplied tests cover primitive filtering and loader composition, but not Scanner::with_row_addr_prefilter. Add coverage for plain allow/block scans with SQL refinement, legacy rejection, flat fallback, and ANN appended/unindexed fragments.

Also applies to: 4129-4133, 4784-4790, 4844-4850

🤖 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/scanner.rs` around lines 3975 - 3979, Add
Scanner-level regression tests covering the row-address mask contract through
Scanner::with_row_addr_prefilter: validate allow/block scans with SQL
refinement, rejection of legacy inputs, flat fallback behavior, and ANN scans
spanning appended and unindexed fragments. Exercise the relevant scanner paths,
including the RowAddrMaskFilterExec application, and assert both returned rows
and expected errors for unsupported cases.

Source: Coding guidelines

rust/lance/src/io/exec/row_addr_mask.rs (1)

109-121: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Replace panic-based extraction in both library paths.

  • rust/lance/src/io/exec/row_addr_mask.rs#L109-L121: replace children.pop().expect(...) with explicit error handling.
  • rust/lance/src/dataset/scanner.rs#L2991-L2993: replace external_row_mask.as_deref().unwrap() with pattern matching or contextual error propagation.
🤖 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/exec/row_addr_mask.rs` around lines 109 - 121, Replace
panic-based extraction in RowAddrMaskFilterExec::with_new_children at
rust/lance/src/io/exec/row_addr_mask.rs:109-121 with explicit error handling
that returns a DataFusionResult error if the child is unavailable; retain the
existing validation for exactly one child. Also update the external_row_mask
access in rust/lance/src/dataset/scanner.rs:2991-2993 to use pattern matching or
contextual error propagation instead of unwrap, handling the missing-mask case
without panicking.

Source: Coding guidelines

🧹 Nitpick comments (2)
rust/lance/src/io/exec/row_addr_mask.rs (2)

147-148: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Include the actual _rowid type in the error.

Report row_id_column.data_type() alongside the expected UInt64 type so malformed execution plans are diagnosable.

🤖 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/exec/row_addr_mask.rs` around lines 147 - 148, Update the
error construction in the row ID validation flow to include
row_id_column.data_type() alongside the expected UInt64 type. Preserve the
existing DataFusionError::Internal failure path and type-checking behavior.

Source: Coding guidelines


50-56: 🚀 Performance & Scalability | 🔵 Trivial | 🏗️ Heavy lift

Avoid deep-copying the shared mask on every load.

MaskAndLoader receives a shared Arc<RowAddrMask>, so Arc::unwrap_or_clone normally takes the clone branch and copies the potentially large mask even when inner is absent. Arc::unwrap_or_clone only unwraps when the reference is unique. (doc.rust-lang.org) Consider preserving shared ownership in the loader contract, or adding a shared fast path; only materialize a new mask for intersections.

🤖 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/exec/row_addr_mask.rs` around lines 50 - 56, Update
MaskAndLoader::load to avoid materializing a cloned RowAddrMask when inner is
absent: preserve or return the shared Arc-backed mask through the loader
contract, and only create an owned mask when applying the intersection with
inner.load().await. Keep the existing intersection behavior unchanged.

Source: MCP tools

🤖 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/exec/row_addr_mask.rs`:
- Around line 244-259: Extend mask_and_loader_with_inner_intersects to cover
block-list × allow-list and block-list × block-list combinations in addition to
the existing allow-list × allow-list case. Construct the corresponding
RowAddrMask values, load them through MaskAndLoader, and assert selected and
unselected addresses to verify the expected intersection algebra.
- Around line 215-222: Strengthen apply_mask_missing_rowid_column_errs by
matching the returned DataFusionError::Internal variant and asserting the
expected missing-column message instead of only checking is_err(). Add a
separate test covering a present rowid column with an unsupported data type,
verifying that apply_mask returns the expected Internal error and message for
the wrong-type branch.

---

Outside diff comments:
In `@rust/lance/src/dataset/scanner.rs`:
- Around line 1210-1222: Update the rustdoc for with_row_addr_prefilter to
include a compiling no_run example using its actual signature, and add API links
for RowAddrMask, RowAddrTreeMap, and the relevant scanner methods. Keep the
example synchronized with the current public API and existing documentation
behavior.
- Around line 3975-3979: Add Scanner-level regression tests covering the
row-address mask contract through Scanner::with_row_addr_prefilter: validate
allow/block scans with SQL refinement, rejection of legacy inputs, flat fallback
behavior, and ANN scans spanning appended and unindexed fragments. Exercise the
relevant scanner paths, including the RowAddrMaskFilterExec application, and
assert both returned rows and expected errors for unsupported cases.

In `@rust/lance/src/io/exec/row_addr_mask.rs`:
- Around line 109-121: Replace panic-based extraction in
RowAddrMaskFilterExec::with_new_children at
rust/lance/src/io/exec/row_addr_mask.rs:109-121 with explicit error handling
that returns a DataFusionResult error if the child is unavailable; retain the
existing validation for exactly one child. Also update the external_row_mask
access in rust/lance/src/dataset/scanner.rs:2991-2993 to use pattern matching or
contextual error propagation instead of unwrap, handling the missing-mask case
without panicking.

---

Nitpick comments:
In `@rust/lance/src/io/exec/row_addr_mask.rs`:
- Around line 147-148: Update the error construction in the row ID validation
flow to include row_id_column.data_type() alongside the expected UInt64 type.
Preserve the existing DataFusionError::Internal failure path and type-checking
behavior.
- Around line 50-56: Update MaskAndLoader::load to avoid materializing a cloned
RowAddrMask when inner is absent: preserve or return the shared Arc-backed mask
through the loader contract, and only create an owned mask when applying the
intersection with inner.load().await. Keep the existing intersection behavior
unchanged.
🪄 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: 90670792-f928-4db7-8cee-3313ab4151d4

📥 Commits

Reviewing files that changed from the base of the PR and between 7c82510 and 36a3b67.

📒 Files selected for processing (2)
  • rust/lance/src/dataset/scanner.rs
  • rust/lance/src/io/exec/row_addr_mask.rs

Comment thread rust/lance/src/io/exec/row_addr_mask.rs
Comment thread rust/lance/src/io/exec/row_addr_mask.rs
@JulianYG
JulianYG force-pushed the feat/row-addr-mask-prefilter branch from 36a3b67 to 4198c4e Compare July 19, 2026 15:45
@JulianYG

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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/dataset/scanner.rs (1)

5623-5717: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add test coverage for stable row ids and block-list masks.

The new integration tests only exercise RowAddrMask::from_allowed(...) on TestVectorDataset::new(LanceFileVersion::Stable, false) (stable row ids disabled). Two gaps worth closing:

  • No test uses enable_stable_row_ids: true, despite with_row_addr_prefilter's doc explicitly claiming both row-address and stable-row-id spaces are "handled" — this is exactly the scenario a past review flagged as a correctness risk.
  • No test uses RowAddrMask::from_block(...) at the scanner level. mask_as_index_inputIndexExprResult::exact(mask.clone()) is a new code path for block masks specifically (previously only allow-masks flowed through u64s_as_take_input); the row_addr_mask.rs unit tests cover block masks only for RowAddrMaskFilterExec/MaskAndLoader, not for the plain-scan FilteredReadExec index-input serialization.
🤖 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/scanner.rs` around lines 5623 - 5717, Extend the
row-address scanner tests around row_addr_mask_plain_scan_allow_with_refine and
row_addr_mask_ann_search_only_allowed to construct TestVectorDataset with
enable_stable_row_ids: true and verify allowed row IDs remain correct. Add
scanner-level coverage using RowAddrMask::from_block(...) through the plain-scan
path, asserting the returned rows match the block mask, including any refine
behavior needed to exercise FilteredReadExec index-input serialization.
🤖 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/dataset/scanner.rs`:
- Around line 5623-5717: Extend the row-address scanner tests around
row_addr_mask_plain_scan_allow_with_refine and
row_addr_mask_ann_search_only_allowed to construct TestVectorDataset with
enable_stable_row_ids: true and verify allowed row IDs remain correct. Add
scanner-level coverage using RowAddrMask::from_block(...) through the plain-scan
path, asserting the returned rows match the block mask, including any refine
behavior needed to exercise FilteredReadExec index-input serialization.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Pro Plus

Run ID: 63da2cce-8392-4b14-8a20-6bc24eb1f5f8

📥 Commits

Reviewing files that changed from the base of the PR and between 36a3b67 and 4198c4e.

📒 Files selected for processing (4)
  • rust/lance/src/dataset/scanner.rs
  • rust/lance/src/io/exec.rs
  • rust/lance/src/io/exec/knn.rs
  • rust/lance/src/io/exec/row_addr_mask.rs

@JulianYG

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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/scanner.rs (1)

1222-1224: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document the new public builder with a compiling example.

Scanner::with_row_addr_prefilter is a public API but has no /// documentation. Describe the mask’s allow/block and _rowid semantics, plain/ANN behavior, and add a compiling example with links to RowAddrMask and related scanner methods.

As per coding guidelines: “Document all public APIs with examples and links to relevant structs and methods; keep examples synchronized with actual signatures.”

🤖 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/scanner.rs` around lines 1222 - 1224, Document the
public Scanner::with_row_addr_prefilter builder with /// comments covering
RowAddrMask allow/block behavior, _rowid semantics, and differences between
plain and ANN scans. Add a compiling example using the actual method signature,
linking to RowAddrMask and related Scanner methods with intra-doc links, and
place the documentation directly above the method.

Source: Coding guidelines

🧹 Nitpick comments (1)
rust/lance/src/dataset/scanner.rs (1)

5632-5636: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Give the rstest cases readable names. Replace #[values(false, true)] with named cases in both tests, e.g. #[case::without_stable_row_ids(false)] and #[case::with_stable_row_ids(true)], so failures identify the row-ID mode.

🤖 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/scanner.rs` around lines 5632 - 5636, Update both
affected rstest functions, including
row_addr_mask_plain_scan_allow_block_refine, by replacing #[values(false, true)]
with named #[case] entries for false and true. Name the cases
without_stable_row_ids and with_stable_row_ids so test failures identify the
row-ID mode.

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/scanner.rs`:
- Around line 1222-1224: Document the public Scanner::with_row_addr_prefilter
builder with /// comments covering RowAddrMask allow/block behavior, _rowid
semantics, and differences between plain and ANN scans. Add a compiling example
using the actual method signature, linking to RowAddrMask and related Scanner
methods with intra-doc links, and place the documentation directly above the
method.

---

Nitpick comments:
In `@rust/lance/src/dataset/scanner.rs`:
- Around line 5632-5636: Update both affected rstest functions, including
row_addr_mask_plain_scan_allow_block_refine, by replacing #[values(false, true)]
with named #[case] entries for false and true. Name the cases
without_stable_row_ids and with_stable_row_ids so test failures identify the
row-ID mode.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Pro Plus

Run ID: 47923168-701a-4a1a-bc0c-100436bfc520

📥 Commits

Reviewing files that changed from the base of the PR and between 4198c4e and 4ec8186.

📒 Files selected for processing (1)
  • rust/lance/src/dataset/scanner.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.

Caution

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

⚠️ Outside diff range comments (3)
rust/lance/src/dataset/scanner.rs (3)

5683-5687: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Format the new test assertions with rustfmt. cargo fmt --all -- --check currently fails.

  • rust/lance/src/dataset/scanner.rs#L5683-L5687: format the chained column_by_name(...).as_primitive::<Int32Type>() assertion.
  • rust/lance/src/dataset/scanner.rs#L5731-L5735: format the multiline ANN allowlist assertion.
🤖 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/scanner.rs` around lines 5683 - 5687, Run rustfmt on
the new test assertions in rust/lance/src/dataset/scanner.rs at lines 5683-5687
and 5731-5735: format the chained
column_by_name(...).as_primitive::<Int32Type>() assertion and the multiline ANN
allowlist assertion to match cargo fmt output.

Source: Pipeline failures


1210-1225: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document the new public builder with links and an example.

with_row_addr_prefilter is public but has no usage example or Rustdoc links to relevant APIs such as [RowAddrMask] and the scan execution methods.

As per coding guidelines: “Document all public APIs with examples and links to relevant structs and methods.”

🤖 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/scanner.rs` around lines 1210 - 1225, Expand the
Rustdoc for with_row_addr_prefilter to include links to RowAddrMask and the
relevant scan execution methods, plus a concise example showing how to construct
and apply the mask before running a scan. Keep the existing behavior and
explanation of dataset _rowid semantics unchanged.

Source: Coding guidelines


2935-2947: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Treat mask-backed plain scans as filtered during source planning.

filtered_read_source still derives projection and scan_range_before_filter from the original filter_plan. Consequently, mask-only scans can apply limit/offset before masking, and exact scalar-index predicates can be rewritten here into a refine filter after their predicate columns were omitted from the projection. This can return too few rows or fail evaluating the refine expression.

Carry use_external_mask/effective_filter into source planning: disable pre-mask range pushdown and include refine columns. Add regressions for a masked limit/offset scan and a masked exact scalar-index predicate projecting an unrelated column.

🤖 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/scanner.rs` around lines 2935 - 2947, The
source-planning path still uses the original filter plan for external-mask plain
scans, allowing limit/offset pushdown before masking and omitting columns needed
by rewritten refine predicates. Update filtered_read_source and its
projection/scan-range planning to use use_external_mask and effective_filter,
disabling pre-mask range pushdown while retaining refine columns; add
regressions covering masked limit/offset scans and masked exact scalar-index
predicates projecting an unrelated column.
🤖 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/scanner.rs`:
- Around line 5683-5687: Run rustfmt on the new test assertions in
rust/lance/src/dataset/scanner.rs at lines 5683-5687 and 5731-5735: format the
chained column_by_name(...).as_primitive::<Int32Type>() assertion and the
multiline ANN allowlist assertion to match cargo fmt output.
- Around line 1210-1225: Expand the Rustdoc for with_row_addr_prefilter to
include links to RowAddrMask and the relevant scan execution methods, plus a
concise example showing how to construct and apply the mask before running a
scan. Keep the existing behavior and explanation of dataset _rowid semantics
unchanged.
- Around line 2935-2947: The source-planning path still uses the original filter
plan for external-mask plain scans, allowing limit/offset pushdown before
masking and omitting columns needed by rewritten refine predicates. Update
filtered_read_source and its projection/scan-range planning to use
use_external_mask and effective_filter, disabling pre-mask range pushdown while
retaining refine columns; add regressions covering masked limit/offset scans and
masked exact scalar-index predicates projecting an unrelated column.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Pro Plus

Run ID: 40a759b0-0578-417d-822f-652ceae85d48

📥 Commits

Reviewing files that changed from the base of the PR and between 4198c4e and 4ec8186.

📒 Files selected for processing (1)
  • rust/lance/src/dataset/scanner.rs

@JulianYG

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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/dataset/scanner.rs`:
- Around line 2947-2970: Update the scan validation around use_external_mask and
the full-text-search setup to reject any request combining
with_row_addr_prefilter with full_text_search. Return a descriptive error at the
API boundary before FTS planning or prefilter_source can run, while preserving
existing behavior for plain and vector scans.
🪄 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: 2933c7e5-1ee8-4779-a7ef-77acc4a0d9f5

📥 Commits

Reviewing files that changed from the base of the PR and between 4ec8186 and 4ac24a7.

📒 Files selected for processing (3)
  • rust/lance/src/dataset/scanner.rs
  • rust/lance/src/io/exec/filtered_read.rs
  • rust/lance/src/io/exec/row_addr_mask.rs

Comment thread rust/lance/src/dataset/scanner.rs
@JulianYG
JulianYG force-pushed the feat/row-addr-mask-prefilter branch from 4ac24a7 to cb2a120 Compare July 20, 2026 03:36
@JulianYG

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@JulianYG

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@JulianYG
JulianYG force-pushed the feat/row-addr-mask-prefilter branch from 1520ee2 to a0ef305 Compare August 12, 2026 01:16
@JulianYG

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added the K-changes Latest Gatekeeper recommendation requests changes. label Aug 12, 2026
@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@JulianYG
JulianYG force-pushed the feat/row-addr-mask-prefilter branch 2 times, most recently from 2c6672d to 466c1c2 Compare August 12, 2026 10:44
@lance-format lance-format deleted a comment from JulianYG Aug 13, 2026
@Xuanwo
Xuanwo requested a review from lance-community August 13, 2026 05:29
@lance-gatekeeper
lance-gatekeeper Bot removed the request for review from lance-community August 13, 2026 05:44
@lance-gatekeeper
lance-gatekeeper Bot removed the request for review from lance-community August 14, 2026 05:50
Lets callers pass a serialized RowAddrMask as an allow/block prefilter into
vector, full-text, and plain scans, reusing the scanner's retrieval plan. The
mask feeds the KNN prefilter source on the ANN branch, the FTS prefilter so
BM25 top-k is computed over masked rows, and FilteredReadExec as the row source
for plain scans; a new RowAddrMaskFilterExec honors the mask on the
flat/unindexed-fragment branch.

Addresses lance-format#6852.
Adds `row_addr_allowlist` / `row_addr_blocklist` to `Dataset.scanner`, plus a
`ScannerBuilder.row_addr_prefilter()` setter, so a caller can restrict a scan,
a KNN search, or a full-text search to a precomputed set of row addresses.

Both are serialized RowAddrTreeMap payloads rather than objects. Two Python
extension modules each link their own copy of the lance crates and cannot share
a Rust value, but they can agree on this encoding, so the mask may be built by a
different module than the one that runs the scan. The bytes are decoded through
RowAddrMask::from_serialized_parts, so no binding reimplements the allow/block
combination.
The cross-column compound scorer is a separate exec from the same-column
one and builds its own prefilter, so the external row-address mask has to
reach it independently. Without it the scorer returns rows the caller
excluded.
@JulianYG
JulianYG force-pushed the feat/row-addr-mask-prefilter branch from 466c1c2 to c372d13 Compare August 23, 2026 05:03
@lance-gatekeeper lance-gatekeeper Bot removed the K-changes Latest Gatekeeper recommendation requests changes. label Aug 23, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added the K-approved Latest Gatekeeper recommendation permits acceptance. label Aug 23, 2026
@lance-gatekeeper lance-gatekeeper Bot removed the K-approved Latest Gatekeeper recommendation permits acceptance. label Aug 23, 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 merge with current main preserves the previously verified mask invariants. The updated take path only removes stale or deleted row IDs, so it composes safely with the external mask.

@lance-gatekeeper lance-gatekeeper Bot added the K-approved Latest Gatekeeper recommendation permits acceptance. label Aug 23, 2026
@Xuanwo
Xuanwo merged commit a9374dd into lance-format:main Aug 23, 2026
39 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-python Python bindings enhancement New feature or request K-approved Latest Gatekeeper recommendation permits acceptance.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants