Change the Schema
Add, rename, drop, move and widen a Table's columns without rewriting its data.
Add a column that your pipeline starts recording, such as an exposure time for each frame, rename a column whose name no longer fits, or widen a number that outgrew its type. A schema change publishes a new Table version like any other write, but it writes metadata only: no data file is copied, so the change costs the same for a Table of a thousand rows or a billion. Jobs that pinned an earlier version keep reading it with the schema it was written with.
Before you start
- A Table
framesin the Projectdemo. See Create a Table. - A client that can write, from the Python SDK or the Rust SDK.
Add a column
Add exposure_ms after captured_at, and publish the new version:
main = client.project("demo").branch("main")
changed = main.table("frames").alter_schema(
[add_column(pa.field("exposure_ms", pa.float32()), after="captured_at")],
)
print(changed.schema())
commit = main.commit()
commit.update_table(changed)
commit.publish()alter_schema returns the next version without publishing it; update_table
stages it and publish makes it visible, as for any write. An added column must
be nullable, and every existing row reads it as NULL. Without after, the
column goes last. To give existing rows values, write them afterwards with
patch_rows,
or add the column and its values in one step as
Add columns shows.
Change existing columns
Pass several changes to make them in one version. They apply in order, so a later change names a column by the name an earlier one gave it:
main = client.project("demo").branch("main")
changed = main.table("frames").alter_schema(
[
rename_column("exposure_ms", "exposure"),
widen_type("exposure", pa.float64()),
move_column("exposure", after="camera"),
]
)
commit = main.commit()
commit.update_table(changed)
commit.publish()The Python SDK builds each change with a function, and the Rust SDK with a
variant of SchemaChange:
| Change | Python | Rust | Rule |
|---|---|---|---|
| Add a column or a struct field | add_column(field, after=None) | AddColumn { field, after } | The field must be nullable. Existing rows read NULL. |
| Drop a column or field | drop_column(path) | DropColumn { path } | A column the Table is partitioned or sorted by cannot be dropped. |
| Rename a column or field | rename_column(path, name) | RenameColumn { path, name } | Values are kept. |
| Let a column hold nulls | set_nullable(path) | SetNullable { path } | A nullable column cannot become NOT NULL. |
| Widen a number | widen_type(path, data_type) | WidenType { path, data_type } | Only without loss, such as int32 to int64 or float32 to float64. |
| Move a column or field | move_column(path, after=None) | MoveColumn { path, after } | Without after, the column moves first. |
A path names a top-level column by its name. To reach a field inside a struct
column, give the names from the top-level column down: a sequence of names in
Python, or ColumnPath::nested([...]) in Rust.
Verify the result
schema() returns a version's schema without reading any rows. Read it on the
version that alter_schema returned, or open the Table again from the branch's
new head after you publish.
Troubleshooting
The SDK checks every change against the version you called it on before it writes anything, so a refused change publishes nothing.
| Problem | Cause |
|---|---|
| The added column must be nullable | The added field is not nullable. |
| A change names a missing column | The path does not exist in the version, or an earlier change in the same call renamed or dropped it. |
| The type cannot change | The new type loses values, such as int64 to int32 or an integer to a float. Add a new column and write the converted values into it instead. |
| The changes leave the schema as it is | Every change was already true of the schema. |
How it works
Each column has a stable field ID, and data files store values by field ID, not
by name. A rename or a move therefore changes only the schema in the version's
metadata, and an added column reads NULL until files for it exist. See
Schema changes.