For Blob v2 output columns on data storage version 2.2+, Geneva checkpoints compact descriptors instead of the payload bytes and writes payloads through PyLance’s bulk blob writer, which significantly reduces checkpoint I/O for large backfills. This requires
pylance>=9.0.0b24.
Writing blob columns from UDFs
Blob v1
For a scalar UDF, returnbytes, set data_type to pa.large_binary(), and add the field_metadata that marks the column as blob-encoded:
pa.RecordBatch) UDF is similar — return a pa.large_binary() array:
Blob v2
The simplest form is a scalar UDF whosedata_type is BlobType() — return the payload as bytes (or None):
lance.blob_field(...) child. This is the pattern Geneva’s large-scale image pipelines use — the struct carries the payload plus any per-row metadata (an error string, dimensions, a content hash, and so on):
bytes (or None); URI-style descriptors like {"uri": ...} are not accepted. A batched UDF builds the struct explicitly, using lance.blob_array(...) for the blob child:
Reading blob columns in UDFs
Blob v1
Blob v1 columns arrive in scalar UDFs as lazyBlobFile objects — call .read() to fetch the payload:
Blob v2
Blob v2 payloads arrive asbytes. Reference a nested blob with its dotted path via the (udf, input_columns) tuple form:
Reading blobs back
Table.take_blobs returns lazy BlobFile handles for both encodings. Use the dotted path for a blob nested in a struct:
API Reference
- UDF —
@udfdecorator for defining blob-producing and blob-consuming functions - Table —
add_columns(),backfill(),take_blobs() - Lance blob guide — the underlying Blob v1/v2 storage model