mirror of
https://github.com/lancedb/lancedb.git
synced 2026-10-13 15:22:30 +00:00
Versioning and branching are properties of a table, not steps in getting data in, so they join the Table group. Consistency stays with Ingestion, where the question it answers -- when do other writers' rows become visible -- is asked. The Ingesting Data page was in the Table group while an Ingestion overview existed separately, so the two are merged. The large-dataset section was duplicated between it and the insert page; the insert page keeps it. Schema and Data Evolution covered two different things under one title. Changing a table's shape stays in Table management; deriving values from data already there becomes a Feature engineering page, next to computed columns and functions, which are the same job at larger scale.
439 lines
16 KiB
Plaintext
439 lines
16 KiB
Plaintext
---
|
|
title: "Schema evolution"
|
|
sidebarTitle: "Schema Evolution"
|
|
description: Learn how to manage table schemas in LanceDB, including adding, altering, and dropping columns.
|
|
icon: "boxes-stacked"
|
|
---
|
|
import {
|
|
PySchemaAddSetup as SchemaAddSetup,
|
|
TsSchemaAddSetup as TsSchemaAddSetup,
|
|
RsSchemaAddSetup as RsSchemaAddSetup,
|
|
PyAddColumnsDefaultValues as AddColumnsDefaultValues,
|
|
TsAddColumnsDefaultValues as TsAddColumnsDefaultValues,
|
|
RsAddColumnsDefaultValues as RsAddColumnsDefaultValues,
|
|
PyAddColumnsNullable as AddColumnsNullable,
|
|
TsAddColumnsNullable as TsAddColumnsNullable,
|
|
RsAddColumnsNullable as RsAddColumnsNullable,
|
|
PySchemaAlterSetup as SchemaAlterSetup,
|
|
TsSchemaAlterSetup as TsSchemaAlterSetup,
|
|
RsSchemaAlterSetup as RsSchemaAlterSetup,
|
|
PyAlterColumnsRename as AlterColumnsRename,
|
|
TsAlterColumnsRename as TsAlterColumnsRename,
|
|
RsAlterColumnsRename as RsAlterColumnsRename,
|
|
PyAlterColumnsDataType as AlterColumnsDataType,
|
|
TsAlterColumnsDataType as TsAlterColumnsDataType,
|
|
RsAlterColumnsDataType as RsAlterColumnsDataType,
|
|
PyAlterColumnsNullable as AlterColumnsNullable,
|
|
TsAlterColumnsNullable as TsAlterColumnsNullable,
|
|
RsAlterColumnsNullable as RsAlterColumnsNullable,
|
|
PyAlterColumnsMultiple as AlterColumnsMultiple,
|
|
TsAlterColumnsMultiple as TsAlterColumnsMultiple,
|
|
PyAlterColumnsWithExpression as AlterColumnsWithExpression,
|
|
TsAlterColumnsWithExpression as TsAlterColumnsWithExpression,
|
|
RsAlterColumnsMultiple as RsAlterColumnsMultiple,
|
|
RsAlterColumnsWithExpression as RsAlterColumnsWithExpression,
|
|
PySchemaDropSetup as SchemaDropSetup,
|
|
TsSchemaDropSetup as TsSchemaDropSetup,
|
|
RsSchemaDropSetup as RsSchemaDropSetup,
|
|
PyDropColumnsSingle as DropColumnsSingle,
|
|
TsDropColumnsSingle as TsDropColumnsSingle,
|
|
RsDropColumnsSingle as RsDropColumnsSingle,
|
|
PyDropColumnsMultiple as DropColumnsMultiple,
|
|
TsDropColumnsMultiple as TsDropColumnsMultiple,
|
|
RsDropColumnsMultiple as RsDropColumnsMultiple,
|
|
PyAlterVectorColumn as AlterVectorColumn,
|
|
TsAlterVectorColumn as TsAlterVectorColumn,
|
|
RsAlterVectorColumn as RsAlterVectorColumn,
|
|
PySchemaFieldMetadataMerge as SchemaFieldMetadataMerge,
|
|
TsSchemaFieldMetadataMerge as TsSchemaFieldMetadataMerge,
|
|
RsSchemaFieldMetadataMerge as RsSchemaFieldMetadataMerge,
|
|
PySchemaFieldMetadataReplace as SchemaFieldMetadataReplace,
|
|
TsSchemaFieldMetadataReplace as TsSchemaFieldMetadataReplace,
|
|
RsSchemaFieldMetadataReplace as RsSchemaFieldMetadataReplace,
|
|
} from '/snippets/tables.mdx';
|
|
|
|
Schema evolution enables non-breaking modifications to a database table's structure — such as adding columns, altering data types, or dropping fields — to adapt to evolving data requirements without service interruptions.
|
|
LanceDB supports ACID-compliant schema evolution through granular operations (add/alter/drop columns), allowing you to:
|
|
|
|
* Iterate Safely: Modify schemas in production with versioned datasets and backward compatibility
|
|
* Scale Seamlessly: Handle ML model iterations, regulatory changes, or feature additions
|
|
* Optimize Continuously: Remove unused fields or enforce new constraints without downtime
|
|
|
|
## Schema evolution operations {#schema-evolution-operations}
|
|
|
|
LanceDB supports four primary schema evolution operations:
|
|
|
|
1. **Adding new columns**: Extend your table with additional attributes
|
|
2. **Altering existing columns**: Change column names, data types, or nullability
|
|
3. **Updating field metadata**: Attach or change per-column Arrow metadata
|
|
4. **Dropping columns**: Remove unnecessary columns from your schema
|
|
|
|
|
|
<Tip title="Schema Evolution Performance">
|
|
Schema evolution operations are applied immediately but do not typically require rewriting all data. However, data type changes may involve more substantial operations.
|
|
</Tip>
|
|
|
|
Each schema evolution operation commits a new table version and returns status metadata such as
|
|
the committed `version`. Run these operations from a mutable table handle; if you checked out an
|
|
older version for reads, call `checkout_latest` / `checkoutLatest` before modifying the schema.
|
|
|
|
## Add new columns {#add-new-columns}
|
|
|
|
You can add new columns to a table with the [`add_columns`](https://lancedb.github.io/lancedb/python/python/#lancedb.table.Table.add_columns)
|
|
method in Python, [`addColumns`](https://lancedb.github.io/lancedb/js/classes/Table/#addcolumns) in TypeScript/JavaScript, or `add_columns` in Rust.
|
|
New columns are populated based on SQL expressions you provide.
|
|
|
|
|
|
### Set up the example table {#set-up-the-example-table}
|
|
|
|
First, let's create a sample table with product data to demonstrate schema evolution:
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{SchemaAddSetup}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
|
|
{TsSchemaAddSetup}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="Rust" language="Rust" icon="rust">
|
|
{RsSchemaAddSetup}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
<Note>
|
|
Columns derived from existing data -- SQL expressions over other columns -- are
|
|
covered in [Data evolution](/feature-engineering/data-evolution), because
|
|
deriving values is a feature-engineering job rather than a schema one.
|
|
</Note>
|
|
|
|
### Add columns with default values {#add-columns-with-default-values}
|
|
|
|
Add boolean columns with default values for status tracking:
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{AddColumnsDefaultValues}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
|
|
{TsAddColumnsDefaultValues}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="Rust" language="Rust" icon="rust">
|
|
{RsAddColumnsDefaultValues}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
### Add nullable columns {#add-nullable-columns}
|
|
|
|
Add timestamp columns that can contain NULL values:
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{AddColumnsNullable}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
|
|
{TsAddColumnsNullable}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="Rust" language="Rust" icon="rust">
|
|
{RsAddColumnsNullable}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
<Warning title="NULL Values in New Columns">
|
|
When adding columns that should contain NULL values, be sure to cast the NULL to the appropriate type, e.g., `cast(NULL as timestamp)`.
|
|
</Warning>
|
|
|
|
## Alter existing columns {#alter-existing-columns}
|
|
|
|
You can alter columns using the [`alter_columns`](https://lancedb.github.io/lancedb/python/python/#lancedb.table.Table.alter_columns)
|
|
method in Python, [`alterColumns`](https://lancedb.github.io/lancedb/js/classes/Table/#altercolumns) in TypeScript/JavaScript, or `alter_columns` in Rust. This allows you to:
|
|
|
|
- Rename a column
|
|
- Change a column's data type
|
|
- Modify nullability (whether a column can contain NULL values)
|
|
|
|
|
|
### Set up the example table {#set-up-the-example-table-2}
|
|
|
|
Create a table with a custom schema to demonstrate column alterations:
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{SchemaAlterSetup}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
|
|
{TsSchemaAlterSetup}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="Rust" language="Rust" icon="rust">
|
|
{RsSchemaAlterSetup}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
### Rename columns {#rename-columns}
|
|
|
|
Change column names to better reflect their purpose:
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{AlterColumnsRename}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
|
|
{TsAlterColumnsRename}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="Rust" language="Rust" icon="rust">
|
|
{RsAlterColumnsRename}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
### Change data types {#change-data-types}
|
|
|
|
Convert column data types for better performance or compatibility:
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{AlterColumnsDataType}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
|
|
{TsAlterColumnsDataType}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="Rust" language="Rust" icon="rust">
|
|
{RsAlterColumnsDataType}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
### Make columns nullable {#make-columns-nullable}
|
|
|
|
You can alter columns to contain NULL values:
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{AlterColumnsNullable}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
|
|
{TsAlterColumnsNullable}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="Rust" language="Rust" icon="rust">
|
|
{RsAlterColumnsNullable}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
Changing a column to nullable affects future writes and merges too: missing values are accepted
|
|
only when the target column is nullable.
|
|
|
|
### Multiple changes at once {#multiple-changes-at-once}
|
|
|
|
Apply several alterations in a single operation:
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{AlterColumnsMultiple}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
|
|
{TsAlterColumnsMultiple}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="Rust" language="Rust" icon="rust">
|
|
{RsAlterColumnsMultiple}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
### Expression-based type changes {#expression-based-type-changes}
|
|
|
|
For transformations that are not simple casts (for example, converting `"$100"` to an integer), use a SQL-expression column add, then drop and rename:
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{AlterColumnsWithExpression}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
|
|
{TsAlterColumnsWithExpression}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="Rust" language="Rust" icon="rust">
|
|
{RsAlterColumnsWithExpression}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
### Alter embedding types and dimensions {#alter-embedding-types-and-dimensions}
|
|
|
|
It's quite common to need to change an embedding column's schema, in case a new model becomes available with a different embedding dimension.
|
|
- In Python, the example shows an in-place type update when the cast is compatible.
|
|
- In TypeScript and Rust, the example shows a dimension change (`384 -> 1024`), which cannot be cast in-place.
|
|
|
|
For dimension changes, use this 3-step pattern: add a new column with the target type, drop the old column, then rename the new column to the original name.
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{AlterVectorColumn}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
|
|
{TsAlterVectorColumn}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="Rust" language="Rust" icon="rust">
|
|
{RsAlterVectorColumn}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
<Warning>
|
|
**`FixedSizeList` Dimension Changes in TypeScript and Rust**
|
|
|
|
`alterColumns` / `alter_columns` can cast between compatible types, but changing `FixedSizeList` dimensions (for example `384 -> 1024`) is not a compatible cast.
|
|
For such cases, use `addColumns` / `add_columns` (with `arrow_cast`), then `dropColumns` / `drop_columns`, then rename the replacement column.
|
|
</Warning>
|
|
|
|
<Warning title="Data Type Changes">
|
|
Changing data types requires rewriting the column data and may be resource-intensive for large tables. Renaming columns or changing nullability is more efficient as it only updates metadata.
|
|
</Warning>
|
|
|
|
## Update field metadata {#update-field-metadata}
|
|
|
|
Each column in a LanceDB table can carry a small key/value map of Arrow field metadata — useful
|
|
for annotating columns with units, provenance, PII flags, embedding model versions, or any other
|
|
schema-level context your application needs.
|
|
|
|
Use [`update_field_metadata`](https://lancedb.github.io/lancedb/python/python/#lancedb.table.Table.update_field_metadata)
|
|
in Python, [`updateFieldMetadata`](https://lancedb.github.io/lancedb/js/classes/Table/#updatefieldmetadata)
|
|
in TypeScript/JavaScript, or `update_field_metadata` in Rust to add, change, or remove these
|
|
key/value pairs without rewriting the column data. Each call commits a new table version and returns
|
|
the new `version`.
|
|
|
|
Each update targets one field by **dot-path**: top-level columns are addressed by name (for
|
|
example `"embedding"`), and nested fields by their full path (for example `"address.zip"`). By
|
|
default, the keys you pass are **merged** into the field's existing metadata — keys you do not
|
|
mention are preserved, and passing `None` (Python) or `null` (TypeScript) deletes a key. Set
|
|
`replace: true` to swap the field's entire metadata map instead of merging.
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{SchemaFieldMetadataMerge}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
|
|
{TsSchemaFieldMetadataMerge}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="Rust" language="Rust" icon="rust">
|
|
{RsSchemaFieldMetadataMerge}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
To overwrite a field's metadata entirely instead of merging, set `replace` to `true`:
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{SchemaFieldMetadataReplace}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
|
|
{TsSchemaFieldMetadataReplace}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="Rust" language="Rust" icon="rust">
|
|
{RsSchemaFieldMetadataReplace}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
<Tip>
|
|
You can pass multiple updates in a single call to change metadata on several fields at once —
|
|
each call commits a single new table version.
|
|
</Tip>
|
|
|
|
### Canonical metadata keys {#canonical-metadata-keys}
|
|
|
|
You can use any string as a metadata key. By convention, LanceDB treats keys prefixed with
|
|
`lancedb:` as canonical. LanceDB Enterprise displays these keys in the UI, and agents can rely
|
|
on finding this information in a consistent place. Use them when they fit your use case:
|
|
|
|
| Key | Purpose | Example |
|
|
| --- | --- | --- |
|
|
| `lancedb:description` | Human-readable description of the field. | `"CLIP embedding of the product image"` |
|
|
| `lancedb:tag:<name>` | User-defined key/value tag, where the suffix names the tag category. | `"lancedb:tag:model": "clip"` |
|
|
| `lancedb:logical-column` | Groups related columns into one logical column. For example, `feature_v1` and `feature_v2` might belong to the same logical column. | `"lancedb:logical-column": "feature"` |
|
|
| `lancedb:status` | Life cycle state of the column: `production`, `candidate`, `deprecated`, or `archived`. | `"lancedb:status": "production"` |
|
|
|
|
<Note>
|
|
These keys are conventions, not enforced constraints. LanceDB does not validate their values,
|
|
but following the conventions keeps your tables consistent with Enterprise tooling.
|
|
</Note>
|
|
|
|
## Drop columns {#drop-columns}
|
|
|
|
You can remove columns using the [`drop_columns`](https://lancedb.github.io/lancedb/python/python/#lancedb.table.Table.drop_columns)
|
|
method in Python, [`dropColumns`](https://lancedb.github.io/lancedb/js/classes/Table/#dropcolumns) in TypeScript/JavaScript, or `drop_columns` in Rust.
|
|
|
|
|
|
### Set Up the example table {#set-up-the-example-table-3}
|
|
|
|
Create a table with temporary columns that we'll remove:
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{SchemaDropSetup}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
|
|
{TsSchemaDropSetup}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="Rust" language="Rust" icon="rust">
|
|
{RsSchemaDropSetup}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
### Drop single columns {#drop-single-columns}
|
|
|
|
Remove individual columns that are no longer needed:
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{DropColumnsSingle}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
|
|
{TsDropColumnsSingle}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="Rust" language="Rust" icon="rust">
|
|
{RsDropColumnsSingle}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
### Drop multiple columns {#drop-multiple-columns}
|
|
|
|
Remove several columns at once for efficiency:
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{DropColumnsMultiple}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
|
|
{TsDropColumnsMultiple}
|
|
</CodeBlock>
|
|
|
|
<CodeBlock filename="Rust" language="Rust" icon="rust">
|
|
{RsDropColumnsMultiple}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
<Warning title="Irreversible Column Deletion">
|
|
Dropping columns cannot be undone. Make sure you have backups or are certain before removing columns.
|
|
</Warning>
|