Pattern: Large Inputs
Use this when a step reads a large upstream table and needs only some of its columns or rows.
A parquet input with no annotation is read with pandas, in full, before your function runs.
Annotate the parameter duckdb.DuckDBPyRelation or pl.LazyFrame and nothing is read up
front: the step’s own query decides which columns and row groups are read. Barca has no
columns= or where= option on inputs=.
| Annotation | What is read |
|---|---|
none, pd.DataFrame, pl.DataFrame, pyarrow.Table |
the whole parquet file, before the function runs |
duckdb.DuckDBPyRelation, pl.LazyFrame |
the file’s metadata; then the columns the step’s query uses, and the row groups its filter cannot rule out |
Example
Section titled “Example”import duckdbimport polars as plfrom barca import asset
@asset()def events() -> duckdb.DuckDBPyRelation: return duckdb.sql(""" select range as id, range % 10 as bucket, 'user-' || (range % 100) as name from range(100000) """)
@asset(inputs={"events": events})def eager(events) -> dict: # no annotation: the whole file is read with pandas before this runs return {"type": type(events).__name__, "rows": len(events), "columns": list(events.columns)}
@asset(inputs={"events": events})def per_bucket(events: duckdb.DuckDBPyRelation) -> duckdb.DuckDBPyRelation: # only the `bucket` column is read return events.aggregate("bucket, count(*) as n").order("bucket")
@asset(inputs={"events": events})def bucket_3(events: pl.LazyFrame) -> pl.LazyFrame: return events.filter(pl.col("bucket") == 3).select("id", "name")
@asset(inputs={"_events": events})def after_events(_events) -> dict: return {"ran": True, "received": repr(_events)}This needs duckdb, polars and barca[parquet] installed.
barca get eager,per_bucket,bucket_3,after_events pipeline.pyWhat barca does
Section titled “What barca does”All five steps run. eager received a pandas DataFrame of every row and column
("rows": 100000, "type": "DataFrame"). per_bucket and bucket_3 return a relation and a
lazy frame. Barca executes them into the step’s parquet file when the step ends, and
barca get prints a pointer to the file, not the rows:
per_bucket: success{ "_barca_artifact": { "format": "parquet", "path": ".barca/artifacts/pipeline.py--per_bucket/1cbb617a...759caa.parquet", "size_bytes": 462 }}after_events ran after events and received None: a _ input is never loaded.
To look at the stored results, use barca sql:
$ barca sql "select * from per_bucket limit 3"bucket n0 100001 100002 10000barca status pipeline.py shows each result’s shape (10 rows x 2 cols for per_bucket), and
barca stats <asset> pipeline.py shows how long a step took.
Going to pandas
Section titled “Going to pandas”If a step needs pandas, take a DuckDB relation, narrow or aggregate it, and convert the
result: events.filter("bucket = 3").project("id").df(). .df() builds a DataFrame of
whatever the relation selects, so calling it on the unnarrowed input is the full read the
annotation was meant to avoid.
Limits
Section titled “Limits”- A declared input is always loaded unless its name starts with
_, whether or not the function uses it. Barca warns at plan time about a step that never uses one of its inputs; the warning is shown in Ordering-Only Dependencies. Remove an unused input, or rename it_<name>(the key ininputs=and the parameter) when it is there for ordering only. - Only parquet artifacts can be read lazily. A json or pickle input is deserialized whole, whatever the annotation.
- Skipping rows needs clustering. Reading only the needed columns always works. A filter
skips a row group only when that group’s min/max statistics exclude the value, which
requires the data to be sorted on the filtered column. In the example
bucketcycles through 0 to 9 in every row group, sobucket_3skips no row group. Sort the upstream step’s output on the column downstream steps filter by. Barca does not sort what a step writes. - Barca does not check that a lazy step narrows its input. A step that annotates
duckdb.DuckDBPyRelationand calls.df()on it reads everything. - Annotations are read from the source. Use the conventional names (
pd,pl,pyarrow,duckdb). - Remote artifacts. A lazy input is read in place, fetching only the byte ranges the query touches, when every reader of the artifact in that phase is lazy. An eager input is downloaded whole, once. See Remote storage.
- Steps that use DuckDB share one connection per worker process. See Anti-Patterns.
The same material is in the terminal manual: barca docs big-inputs. Input annotations are
listed in barca docs types.