lance-format / lance-format/lance

Should we provide a query interface from rowId to rowAddr to the non-Rust side?

Open
#4,772 13 comments 0 reactions 1 assignee View on GitHub

@steFaiz is already working on this.

Since Sep 19, 2025.

question rust
Dominant language
Rust
Stars
7.1k
Forks
852
Avg merge
3d 18h
Merged PRs (30d)
272

Description

The stable rowId is a crucial feature of Lance, giving it usable primary key functionality. Currently, the rowIdIndex is a completely internal data structure that plays a vital role in various internal operations such as update, take, and indexed queries. However, these operations are at the Dataset level and cannot be directly utilized by big data engines like Flink, Spark, or Ray.

For example, in the column addition scenario, Lance needs to align new data with existing rows based on rowId, as illustrated below:

Image

In distributed computing, we need to horizontally partition the dataset for computation by rows (i.e., Fragments), which requires shuffling the data.

Image

Therefore, we need the ability to convert rowId to rowAddress at the computing engine level, so that we can further obtain the FragmentId. Currently, there is no ready-to-use interface for this purpose. As a workaround, I have to SELECT all <RowId, RowAddress> pairs from the source table and perform a join with the new data to obtain the corresponding RowAddresses. However, this join incurs significant overhead, and even if the column addition involves only a small subset of rows, it still requires scanning the entire source table, which is highly inefficient.

Therefore, I'm wondering if we could expose an interface in the Dataset to query the mapping from rowId to rowAddr:


impl Dataset {
  pub async fn getRowAddress(&self, row_id: u64) -> Option<RowAddress> {
      ...
  }
  // get batch to reduce jni cost
  pub async fn getBatchRowAddress(&self, row_ids: &[u64]) -> &[RowAddress] {
      ...
  }
}

Or alternatively, implement a delegated row ID index at the Java/Python FFI (Rust) boundary to enable efficient rowId-to-rowAddr lookups from non-Rust environments.


Struct LanceRowIdIndex {
    inner: RowIdIndex
}

impl LanceRowIdIndex {
    pub async fn open(dataset: &Dataset) -> LanceRowIdIndex {
        ...
    }
  
    pub async fn get(&self, row_id: u64) -> Option<RowAddress> {
        ...
    }

    // get batch to reduce jni cost
    pub async fn getBatch(&self, row_ids: &[u64]) -> &[RowAddress] {
         ...
    }
}

Do you think this functionality is necessary? @majin1102 @jackye1995 @yanghua

I'd be very happy to implement this feature!

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.