feat: distributed update_columns for overwriting existing columns - #5261
Open
FANNG1 wants to merge 11 commits into
Open
feat: distributed update_columns for overwriting existing columns#5261FANNG1 wants to merge 11 commits into
FANNG1 wants to merge 11 commits into
Conversation
added 10 commits
July 27, 2026 11:12
Assert the returned rows_updated in the two tests that discarded it, which also clears ruff F841, and reflow the docs example so `ruff format --check` is clean for the files this branch touches. Claude-Session: https://claude.ai/code/session_016cKDCcCvDW9YVxT7Ea7Qtb
Ray workers cannot import the test module -- it imports pytest, which is absent from the worker environment -- so every transform that referenced a test-module global failed to deserialize. Move the two helpers that cross the Ray boundary into _ray_test_support, which exists precisely to be importable from workers, and replace the bare asserts inside two transforms with explicit raises: pytest rewrites `assert` into calls on `_pytest`, which the pickled closure then drags along. Claude-Session: https://claude.ai/code/session_016cKDCcCvDW9YVxT7Ea7Qtb
yanghua
self-requested a review
July 28, 2026 07:55
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #5260.
Adds
lance_ray.update_columns(), a distributed operation that overwritesexisting columns of a Lance dataset. Until now
add_columns,add_columns_fromandmerge_columns_fromcould only add new columns, sore-running an enrichment stage — recomputing labels for a date range, or
regenerating embeddings after a model upgrade — meant rewriting the whole table.
How it works
A dataset snapshot is pinned on the driver, then each fragment is processed by
exactly one Ray task that scans, filters, transforms and rewrites only its own
fragment. Keeping scan and rewrite together in one task avoids the Ray Data
shuffle and regrouping that
merge_columns_fromneeds for externally createddata.
The rewrite uses Lance's
RewriteColumnsupdate mode, so rows do not move,_rowaddrstays stable, and columns that were not named keep their originaldata files. The driver collects every worker's fragment metadata and issues a
single
LanceOperation.Updatecommit — a failure in any fragment aborts the runwithout a transaction, so the dataset is never left half-updated.
Transform results are streamed to Lance as a
RecordBatchReaderrather thanmaterialized per fragment.
API notes
columnstakes column names, not a schema.update_columnsonly overwritescolumns that already exist, so each target's Arrow type and nullability are
fixed by the dataset — a caller-supplied schema could only either repeat what
the dataset already says or be an error. Taking names keeps the redundancy out
of the signature, and avoids the trap where
pa.schema([("price", pa.float64())])silently defaults to
nullable=Trueand mismatches a non-nullable target.The transform result is reordered to
columnsand cast to the dataset's typeswith
safe=True. One limit is documented rather than papered over: Arrow's safecast range-checks integers and time units but not float narrowing, so
returning a
float64for afloat32column rounds (and overflows toinf)silently. The docstring and
docs/src/data-evolution.mdsay so and recommendproducing the column's own type when precision matters.
Everything checkable is checked on the driver before any Ray task starts —
unknown column, metadata column, nested path, duplicate, struct target, blob
write target, bare-string
columns— so a bad call cannot rewrite half thefragments before failing.
Limitations
offsets Lance needs to advance
_row_last_updated_at_version, so the changewould be invisible to CDF consumers (Update op with UpdateMode.RewriteColumns does not advance _row_last_updated_at_version lance#6734). Raises
NotImplementedErrorrather than committing something wrong.update targets.
fit — matching rows should be reasonably concentrated.
relying on them.
Tests
50 tests in
tests/test_update_columns.pycovering: multi-fragment andmulti-batch updates, filters and partial fragment coverage, multi-column
updates, the no-op path when a filter matches nothing, the transform contract
(row count, row order, output columns,
BatchUDF, casting, non-nullabletargets), physical correctness (
_rowaddrpreservation, untouched data files,time travel, deleted rows), transaction behavior (stale snapshot, concurrent
append rebase), leaf field ids for
listand fixed-size-list columns, blob v1and v2 input, namespace-only resolution, and driver-side rejection with a
dataset fingerprint asserting nothing was written.
ruff checkis clean.ruff format --checkreports the same three files asmain; none are touched here.https://claude.ai/code/session_016cKDCcCvDW9YVxT7Ea7Qtb