Define a chunking Function
A Function that returns alist produces more than one value per input row.
A chunker is a Function whose output is a list — of structs, of strings, of
anything — registered like any other Function. See
Create a Function for CPU, GPU and remote-service
Functions, and scalar versus batch calling, if you have not registered one
before.
A function that splits text into fixed-size passages turns a documents
table into one row per passage. Registration details, environment and
dependency declarations, and how a version stays immutable once rows are
filled from it, are the same for a chunker as for any other Function —
register it from Python, or the same function from SQL with
CREATE FUNCTION:
Source: documents
Explode it in a query
Wrap the function call inUNNEST in the SELECT list, with an alias: it
yields one row per element of the list the function returns, with every
other selected column repeated. Reference the exploded struct’s fields
through that alias in a query over this one:
doc_id and title from its parent. This is the fastest way to
check a chunker before committing to a materialized view: run it over a few
rows and inspect the output shape.
Video into frames
Chunking a blob column is the same shape, with the chunker producing timestamps rather than text spans, and a second Function pulling the actual frame for each one.videos holds raw clips in a
Blob v2 column, with each row’s duration
already known:
Source: videos
A chunker that samples one timestamp per second needs no blob access at all
— it only looks at
duration_seconds:
BlobReader,
rather than loading the whole clip — and returns one JPEG per call:
videos into one row per sampled
timestamp, then call extract_frame on each row to produce its image:
FROM position yields one row per list element the same way
regardless of what the list holds; whether the second step produces a blob,
a plain value, or another struct does not change the explosion.
Persist it as a materialized view
Wrap either query inCREATE MATERIALIZED VIEW
to keep a real table that stays current as the source changes, instead of
recomputing the explosion on every query:
chunks (1:N expansion)
The view refreshes like any other materialized view: new source rows are
chunked and inserted, deleted source rows drop their children, and an
updated row’s old children are replaced by freshly chunked ones on the next
refresh. A single
UNNEST(...) —
whether unnesting a Function’s list output directly, as above, or an
existing list column — is the only lateral expansion a materialized view
can carry, and it can’t be combined with GROUP BY, so keep aggregation or
further curation in a second step over the chunked table.