feat: add support for reading deletion-vector tables - #18
Conversation
Switch `load_as_polars` to Polars' native Delta reader (`pl.scan_delta`, `use_pyarrow=False`), which reads deletion-vector tables (modern Databricks / Unity Catalog tables) that the legacy pyarrow path rejects with `DeltaProtocolError`. Native DV support landed in polars 1.40.0, so the floor is raised to >=1.40.0 and the now-unused `pyarrow` extra is dropped. The `partition_filter` DSL and `PartitionFilterOperator` enum are removed; filter with native Polars expressions instead. Passing a cached `DeltaTable` to `scan_delta` bypasses Polars' own protocol check, which would silently return all-null columns for column-mapping (and reader-version-2) tables; `load_as_polars` now guards the protocol and raises `DeltaProtocolError` for them. BREAKING CHANGE: the `partition_filter` parameter of `load_as_polars` and the `PartitionFilterOperator` enum are removed; filter with native Polars expressions instead.
|
issue: polars native I suggest keeping both approaches, with a note that if pyarrow partition filtering is used, tables which use deletion vectors cannot be read (and enforce this with an exception). |
Good catch! I've reproduced that behavior locally and created and opt-in benchmark test for pytest (opt-in because it can be flaky as it depends on speed - I found no way to verify that the native polars reads the partition metadata other than by simulating high number of partitions and demonstrating the slowdown. Ready for review. |
| 'Polars Delta reader does not support (only version 1 or ' | ||
| f'{MAX_SUPPORTED_READER_VERSION}).' |
There was a problem hiding this comment.
suggestion: remove explicit mention of only version 1 or {MAX_SUPPORTED_READER_VERSION} as this formulation is coupled to the assumption that MAX_SUPPORTED_READER_VERSION == 3 which might change in deltalake (probably will change in the near future as deltalake is adding support for Delta features).
I would unify this version check with the check above (rough formulations):
if version > MAX_SUPPORTED_READER_VERSION or version == NOT_SUPPORTED_READER_VERSION:
f'The table requires reader version {version}, which the native '
f'Polars Delta reader does not support. Supported reader versions are: <= {MAX_SUPPORTED_READER_VERSION}, != {NOT_SUPPORTED_READER_VERSION}'| # count. On object storage each of those is a network request per file, | ||
| # which is where the reviewer's ~4-7s -> ~50s regression came from | ||
| # (pola-rs/polars#20998). This benchmark documents the local trend; it |
There was a problem hiding this comment.
suggestion: I would not mention the number from a specific use case here. Rather, I would make a general statement that the slowdown can be one or more orders of magnitude when reading a small number of partitions from a table with a huge total number of partitions.
| # Fast on tables with many partitions: only the matching partitions are listed. | ||
| df = table_client.load_as_polars( | ||
| partition_filter=[ | ||
| ('country', PartitionFilterOperator.EQUAL, 'CZ'), |
There was a problem hiding this comment.
nitpick: to showcase that the operations produce the same results between the polars-native way and the pyarrow-options-way, it would be nicer if the queries was equivalent.
I think it's good to showcase that IN operator is supported for partition filtering as it is the way to implement an 'OR' condition (since multiple partition filters have 'AND' semantics).
| ('country', PartitionFilterOperator.EQUAL, 'CZ'), | |
| ('country', PartitionFilterOperator.IN, ['CZ', 'SK']), |
Add support for reading deletion-vector tables (modern Databricks / Unity
Catalog) by switching
load_as_polarsto Polars' native Delta reader(
pl.scan_delta) by default. The pyarrow reader rejects such tables withDeltaProtocolError; the native reader reads them. Native DV support landed inpolars 1.40.0, so the floor is raised to >=1.40.0.
partition_filter(andPartitionFilterOperator) are kept, but now route to thepyarrow reader, which pushes the predicate into delta-rs's file enumeration and
prunes partitions — the native reader does not do this efficiently
(pola-rs/polars#20998). The native reader skips non-matching partitions' data but
still handles per-file metadata for every partition, which on object storage is a
network request per file, so reading a few partitions of a many-partition table
can be far slower. The pyarrow path cannot read
deletion-vector tables and raises
DeltaProtocolErrorfor them; read thosenatively and
.filter()the returned LazyFrame instead.Passing a cached
DeltaTabletoscan_deltabypasses Polars' own protocol check,which would silently return all-null columns for column-mapping (and
reader-version-2) tables;
load_as_polarsnow guards the protocol and raisesDeltaProtocolErrorfor them.