🤖 Name your tables on every engine: table_names across the multi-engine backends - #252
🤖 Name your tables on every engine: table_names across the multi-engine backends#252alxmrs wants to merge 3 commits into
Conversation
`table_names` gave ARCO-ERA5's two dimension groups the names `surface` and `atmosphere` instead of `time_latitude_longitude` and `time_level_latitude_longitude`. It only ever reached DataFusion. Route it through the register seam so it means the same thing wherever a Dataset is registered. One naming rule, `df.resolve_table_names`, now serves every adapter: * DuckDB takes `table_names`, keeps registering the flat `era5_surface` tables, and mirrors the groups as views in a schema so `era5.surface` resolves too — the DataFusion spelling, so query text moves between engines unchanged. Pushdown and projection travel through the view. A read-only connection cannot create a schema; that path warns and leaves the flat tables rather than losing the registration. * A plain `SessionContext` splits mixed-dimension Datasets into a schema the way `XarrayContext` does, instead of registering them as one table they cannot be. * `arrow_datasets(ds, name, table_names=...)` returns the split tables named, for Polars and anything else scanning the pyarrow dataset protocol, reading the shared dimension coordinates once. Groups left unnamed keep their joined dimension names. Keys naming a group the Dataset does not have are ignored, so one map can be reused across variable subsets; two groups claiming one name is an error rather than a silent clobber. The geospatial suite's private copy of the split is gone — the harness calls `arrow_datasets`, so benchmark naming cannot drift from the library's. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013LfwhbX9VLmvoN6ka7py5w
| registered under. | ||
| """ | ||
| try: | ||
| con.execute(f"CREATE SCHEMA IF NOT EXISTS {_quote(name)}") |
There was a problem hiding this comment.
con.register only puts things in the temp namespace but this schema is durable. so on a file backed db the views stick around after the session and point at nothing. reopened one and got Table with name era5_surface does not exist!
tried CREATE SCHEMA temp.era5 and duckdb won't allow it, so maybe only mirror on in-memory connections? or at least mention it in limitations.md
| con.register_table(name, read_xarray_table(ds, chunks, **kwargs)) | ||
| return con | ||
|
|
||
| # A mixed-dimension Dataset becomes one table per dimension group |
There was a problem hiding this comment.
the old path did register a mixed dim dataset as one table. on a 4x3 / 4x2x3 fixture i get COUNT(*) = 24 with t2m broadcast across level, so it worked, just weirdly.
no objection to splitting, but it's a break and nothing records it. no test on the old shape and changelog is untouched
| # One group is one table, named `name` — there is no group to | ||
| # tell apart. Without a `name`, it takes the group's own. | ||
| only = name if name else next(iter(names.values()), "scalar") | ||
| return {only: arrow_dataset(ds, chunks, **kwargs)} |
There was a problem hiding this comment.
this branch calls arrow_dataset and the other builds XarrayPushdownDataset, so which kwargs work depends on the data. arrow_datasets(uniform_ds, "x", _iteration_callback=f) is a TypeError, the mixed one is fine.
using XarrayPushdownDataset here too would line them up
| variables, if any, takes ``scalar``. | ||
| **kwargs: Forwarded to | ||
| [arrow_dataset][xarray_sql.backends.pyarrow.arrow_dataset] | ||
| (``batch_size``, ``prefetch``, ``geometry``, ...), applied to |
There was a problem hiding this comment.
since geometry goes to every group it can never work on a mixed dim dataset. geometry dims ['lat', 'lon'] are not columns of the table; available: ['proj']
skip the groups that don't have those dims, or say here that geometry needs a uniform dataset
This feature adds the
table_namesfeature to all engine backends so each SQL engine behaves similar to the native datafusion experience.🤖 below (with human edits).
The
table_nameskeyword only ever reached DataFusion. Since #227 a Dataset can beregistered on DuckDB or scanned by Polars, and on those paths the tables went
back to being named after their dimensions. This routes
table_namesthroughthe register seam, so it means the same thing wherever a Dataset is
registered:
What each engine does
DuckDB.
con.registercan only place an object in DuckDB's temporarynamespace, so each dimension group is still registered flat as
era5_surface,and the groups are additionally mirrored as views in a schema of their own so
era5.surfaceresolves. Both spellings hit the same scan — chunk pruning andcolumn projection travel through the view (pinned by a test: a
WHERE time = ...query reads 1 of 6 chunks and projects two columns). A read-onlyconnection cannot create a schema; that path warns and leaves the flat tables
rather than losing the registration.
A plain
datafusion.SessionContext. It now splits mixed-dimensionDatasets into a schema the way
XarrayContextdoes. Previously it registeredthe whole Dataset as a single table, which a mixed-dimension Dataset cannot
be.
Polars, and anything else consuming the pyarrow dataset protocol, has no
connection object to dispatch on, so it takes the tables directly:
arrow_datasetsis the new public function here —arrow_datasetwants aDataset whose variables share one set of dimensions, and this is the
mixed-dimension form of it. It reads the shared dimension coordinates once for
all the tables it returns, which is a network round-trip saved per dimension
per group on Zarr-backed stores.
Naming rules
One rule,
df.resolve_table_names, serves every adapter:group holding scalar variables, if any, is
scalar.canonical naming map can be reused across Datasets holding different subsets
of the same variables.
one table over the other.
Also here
The geospatial benchmark suite carried its own copy of the split
(
_group_tables), written when the library had no cross-engine version. Itnow calls
arrow_datasets, so benchmark naming cannot drift from thelibrary's.
docs/limitations.mdlisted "mixed-dimension datasets split into one DuckDBtable per dim group" as a sharp edge; it is now the narrower read-only-
connection caveat.
Testing
tests/test_table_names.pyholds the contract in one place: the same namingmap on
XarrayContext, a plainSessionContext, DuckDB, and Polars,including a parity test that runs one SQL string against
era5.surfaceonthree engines and asserts one number. Plus the spellings (dotted and flat),
pushdown through the view, the round-trip back to a Dataset, the read-only
warning, and the two naming rules above.
Full suite: 332 passed, 2 skipped.
ruffandmypyclean.The benchmark cases themselves need ARCO-ERA5 from GCS, so the harness change
was exercised against a synthetic ERA5-shaped Dataset on all three engines
rather than through a suite run.
Not done
CHANGELOG.mdis untouched — itsUnreleasedsection predates both 0.4.0-rc.1and #227, so it looked retired. Happy to add an entry if it is still live.
🤖 Generated with Claude Code
https://claude.ai/code/session_013LfwhbX9VLmvoN6ka7py5w