mirror of
https://github.com/lancedb/lancedb.git
synced 2026-10-13 15:22:30 +00:00
Indexing loses its wrapper group -- Overview, Vector Index, FTS Index, Scalar Index and Build & Repair sit directly in Maintenance now, followed by Compaction, Cleanup and Background Jobs at the same level. Cleanup is new, split out of Compaction: pruning old versions is a distinct Enterprise job (cleanup) from merging files (compact), even though optimize() in OSS bundles both into one call. The retention, disk-usage and failed-transaction material that used to live under Compaction's umbrella moves with it. Background Jobs is new and covers what nothing else does: the job types a deployment runs on its own -- WAL/SPFresh maintenance, cache prewarming, registry archiving and metering export, and the object-teardown job that follows a namespace or view drop. Every entry is grounded against the job-coordinator's public job_type constants, not the internal two-letter wire codes used for registry storage. Five existing pages (Build & Repair, Table, Function, Column Refresh, Materialized View Refresh) gain a one-line job-type note rather than duplicating a page for job types they already document. Storage folds into Deployment: storage/index (choosing a backend) and storage/configuration (configuring one) merge into a single Storage page -- they never overlapped, one is the decision and one is the how-to -- and move under Deployment along with Monitoring. Cloud Providers loses its nesting; its two pages plus Azure sit flat, and the former Overview is retitled Deployment Models so it doesn't collide with the group's own Overview entry. Redirects cover every moved URL.
158 lines
5.9 KiB
Plaintext
158 lines
5.9 KiB
Plaintext
---
|
|
title: "Functions"
|
|
sidebarTitle: "Function"
|
|
description: "Register a Python function once and apply it as a column, for work SQL cannot express."
|
|
icon: code
|
|
keywords: ["udf", "functions", "create_function", "embedding", "feature engineering"]
|
|
---
|
|
|
|
<Badge color="red">Enterprise</Badge>
|
|
|
|
Some columns cannot be written as a SQL expression: an embedding, a model call,
|
|
an image decode. A function is a Python callable registered with the database,
|
|
versioned, and then applied as a column — the code runs where the data is
|
|
rather than pulling rows to your process.
|
|
|
|
Registration is a remote operation. On a local connection `create_function`
|
|
raises `NotImplementedError`; use a
|
|
[computed column](/feature-engineering/refresh-column) instead.
|
|
|
|
<Note>
|
|
In SQL, a function is registered with [`CREATE FUNCTION`](/sql/ddl#functions) and listed with [`SHOW FUNCTIONS`](/sql/show#functions).
|
|
</Note>
|
|
|
|
## Define a function {#define}
|
|
|
|
`@udf` packages a scalar Python callable. Input and output types are inferred
|
|
from annotations:
|
|
|
|
```python
|
|
from lancedb import udf
|
|
|
|
@udf(pip=["numpy==2.2.0"])
|
|
def score(value: float) -> float:
|
|
return value * 2
|
|
```
|
|
|
|
The decorated object stays callable, so `score(1.5)` runs the original function
|
|
locally and unit tests stay ordinary tests.
|
|
|
|
Where annotations cannot express the Arrow type precisely, pass `input_schema`
|
|
and `output_schema` together — one without the other is rejected. Outputs must
|
|
be non-nullable, because a physical NULL is what marks a computed-column row as
|
|
unfilled.
|
|
|
|
## Declare the environment {#environment}
|
|
|
|
The function runs remotely, so its dependencies are part of its definition:
|
|
|
|
| | |
|
|
| --- | --- |
|
|
| `pip` | requirements for the remote environment |
|
|
| `conda`, `conda_channels` | conda packages instead of pip; channels in priority order |
|
|
| `env` | environment variables |
|
|
| `python_version` | remote Python major/minor, defaulting to yours |
|
|
| `gpu` | whether every execution requires a GPU |
|
|
|
|
These are part of the **immutable function version**. Changing a dependency
|
|
produces a new version rather than altering the one already registered, so a
|
|
column filled by version 1 is unaffected by version 2.
|
|
|
|
Declaring them is not optional bookkeeping. If the worker environment differs
|
|
from the one the function was written against, the failures are among the
|
|
hardest to diagnose in the system, because the error rarely names the cause.
|
|
|
|
### Symptoms of an environment mismatch {#mismatch-symptoms}
|
|
|
|
| Symptom | Likely cause |
|
|
| --- | --- |
|
|
| `TypeError: Enum.__new__() missing 1 required positional argument` | `attrs` version mismatch |
|
|
| `TypeError: Can't instantiate abstract class` | package structure differs between versions |
|
|
| `ArrowInvalid: cannot cast`, or serialization errors | NumPy 1.x against 2.x |
|
|
| `ModuleNotFoundError` on the worker | package installed locally but not declared |
|
|
| Model loading failures | PyTorch version mismatch |
|
|
| Permission denied | an API key present locally but absent from `env` |
|
|
|
|
The packages worth pinning explicitly, because a mismatch in them produces the
|
|
errors above rather than a clear one: **numpy, torch, pyarrow, attrs,
|
|
pydantic**.
|
|
|
|
<Note>
|
|
The client version defaults `python_version`, so a function registered from a
|
|
3.11 environment runs on 3.11 unless you say otherwise. That default is usually
|
|
right and occasionally surprising -- pin it when the function is sensitive to it.
|
|
</Note>
|
|
|
|
## Failure handling {#failures}
|
|
|
|
A function that raises fails the job. There is no per-row retry or skip policy
|
|
in the function definition: `@udf` takes no error-handling parameter, so a
|
|
function that calls a flaky external service should handle that itself, inside
|
|
the function body.
|
|
|
|
Letting the job fail is the other option. Since
|
|
[a refresh never revisits a filled row](/feature-engineering/refresh-column#idempotent),
|
|
re-running after a partial failure costs only the rows that did not complete.
|
|
|
|
## What gets packaged {#packaging}
|
|
|
|
<Warning>
|
|
The artifact is a **snapshot**: the function source, plus exactly the
|
|
module-level names it references — modules as imports, importable classes and
|
|
functions as imports, literals inlined.
|
|
|
|
Code that reaches the module namespace another way is rejected where it can be
|
|
seen and unsupported where it cannot: `globals()`, `eval`, `sys.modules`,
|
|
`builtins`. Closures and a non-standard `__builtins__` are rejected outright.
|
|
</Warning>
|
|
|
|
In practice this means a function should be self-contained: take its inputs as
|
|
arguments, import what it needs at module level, and avoid capturing state from
|
|
the surrounding scope.
|
|
|
|
<Note>
|
|
**Enterprise job type:** `create_function`. Registration returns a job because
|
|
the function is baked into an image before the version becomes usable -- see
|
|
below.
|
|
</Note>
|
|
|
|
## Register it {#register}
|
|
|
|
Registration returns a job; the immutable version exists once the job succeeds.
|
|
|
|
```python
|
|
job = db.create_function_async(score)
|
|
version = job.wait()
|
|
```
|
|
|
|
`create_function` is the blocking equivalent. A registered version is fetched
|
|
with `db.get_function(name, version=...)`.
|
|
|
|
## Apply it as a column {#apply}
|
|
|
|
A registered function is applied through `add_columns`, in the `transforms`
|
|
mapping:
|
|
|
|
```python
|
|
table.add_columns(transforms={"doubled": score(table["value"])})
|
|
```
|
|
|
|
A mapping with one function application keeps its scalar or named-struct result
|
|
in the named column. A bare named-struct application expands its result fields
|
|
as one atomic binding, with aliases from `rename(columns=...)`.
|
|
|
|
Filling then works exactly as it does for any computed column — see
|
|
[Computed columns](/feature-engineering/refresh-column) for refresh
|
|
semantics, including the rule that filled rows are never revisited.
|
|
|
|
## What to read next {#next}
|
|
|
|
<CardGroup cols={2}>
|
|
<Card title="Computed columns" icon="table-columns" href="/feature-engineering/refresh-column">
|
|
Refresh semantics, and the SQL alternative.
|
|
</Card>
|
|
<Card title="Embedding functions" icon="vector-square" href="/embedding">
|
|
Built-in embedding providers, which need no registration.
|
|
</Card>
|
|
</CardGroup>
|