lance-format / lance-format/lance
Optimize upsert with partial schema and no index
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 7.1k
- Forks
- 852
- Avg merge
- 3d 18h
- Merged PRs (30d)
- 272
Description
Background
We are migrating from an implementation of merge insert that manually manipulates streams to one that constructs a DataFusion plan and runs optimizers on that plan for optimize it.
The old code path is in execute_uncommitted_impl:
While the new codepath is under execute_uncommitted_v2:
Task
Goal: upsert queries that provide a subset of columns use the new code path.
Lance implements updates as delete plus insert. Therefore, if the user supplies a subset of the columns, we will need to read the existing columns values for updated rows before writing out the new rows. This should be handled by TakeExec.
Caveats
The current implementation has special behavior for how it updates existing rows, which is tested here:
Instead of marked the old rows as deleted and then moving the new versions of those rows to a new file, it marks the updated columns as dropped, and adds new files in the existing fragments. This avoids rewriting large columns if they are not part of the update.
We should find a way to make an optimizer rule that is smart about choosing which write code path to choose.
TODO
- Create a
TakeNodethat implementsUserDefinedLocalNodeCoreand gets turned into aTakeExecwhen applied with a planner. - Add a parameter to merge_insert to choose to use the in-place update write pattern, that will route to the current write behavior. This can default to the new write pattern.
- Alter the
create_planimplementation to add any missing columns from source usingTakeNode. - Add an optimize rule that eliminates
TakeNodethat don't get any columns.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read rust/lance/src/dataset/write/merge_insert.rs, comparing execute_uncommitted_impl with execute_uncommitted_v2 and the existing update behavior around lines 2376-2381. Trace create_plan and the planner path, then implement and verify the TakeNode, merge_insert routing parameter, missing-column handling, and optimizer rule described in the TODO list.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- data-engineering, databases
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100