Repository navigation
PyArrow: Support view types when writing to a partitioned table - #4121
Conversation
| return pc.field(partition_field_name) == value | ||
|
|
||
|
|
||
| def _replace_view_types(arrow_type: pa.DataType) -> pa.DataType: |
There was a problem hiding this comment.
Thanks @DG47 this makes sense to me. Instead of building this recursive function ourself, we can also implement this using the PyArrowSchemaVisitor:
iceberg-python/pyiceberg/io/pyarrow.py
Line 1327 in 0cc389b
There was a problem hiding this comment.
Good idea, done in 75c2fe0. The recursion is gone; _determine_partitions now calls visit_pyarrow(arrow_table.schema, _ConvertViewTypes()), and the visitor lives next to _ConvertToLargeTypes. Unlike that one it keeps the list flavour, nested field names, nullability and metadata, so the cast is a pure view-to-large rewrite. One wrinkle: visit_pyarrow unwraps dictionary types before calling primitive, so the visitor re-applies the dictionary encoding in field, list and map to leave dictionary columns untouched.
Appending an Arrow table with string_view or binary_view columns, which pa.table() produces from a Polars DataFrame, worked for unpartitioned tables but failed for partitioned ones: PyArrow has no group by, filter or take kernels for view types, and pyiceberg-core's bucket and truncate transforms reject them. Cast view types, including nested ones, to their large counterparts before splitting the table into partitions.
75c2fe0 to
9bb7110
Compare
Polars exports Categorical as dictionary<string_view> and List(Categorical) as large_list<dictionary<string_view>>, which exercise the _keep_dictionary paths in _ConvertViewTypes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
kevinjqliu
left a comment
There was a problem hiding this comment.
LGTM! Thanks for the PR @DG47
btw i pushed a small test (66200730f) for polars Categorical and List(Categorical), since those go through the _keep_dictionary path which wasn't covered.
polars exports:
Categorical→dictionary<string_view>(source)List(Categorical)→large_list<dictionary<string_view>>
| # PyArrow has no group by, filter or take kernels for view types, so replace them with their large counterparts | ||
| arrow_schema = visit_pyarrow(arrow_table.schema, _ConvertViewTypes()) |
There was a problem hiding this comment.
😭 feels like we're constantly writing custom code to workaround pyarrow
Closes #4120
Rationale for this change
string_viewandbinary_viewcolumns are accepted on write, and appending them to an unpartitioned table works. Appending them to a partitioned table fails in_determine_partitions, because PyArrow has no group by, filter or take kernels for view types, and the pyiceberg-core bucket and truncate transforms do not accept them either.pa.table(polars_df)produces exactly this shape, since Polars exports strings and binaries as view types over the PyCapsule interface.Depending on the spec, the append fails with
Keys of type string_view,Function 'array_filter' has no kernel matching input types (string_view, bool), orUnsupported data type for bucket transform: Utf8View.This change casts view types, including ones nested in structs, lists and maps, to
large_string/large_binarybefore the table is split into partitions. Tables without view types are not cast. The data files are written the same as forlarge_string/large_binaryinput.One remaining gap is outside this repo: truncate on a binary column already fails for
large_binaryinput in pyiceberg-core (apache/iceberg-rust#3119), and nowbinary_viewinput hits that same error.Are these changes tested?
Yes:
test_determine_partitions_with_view_types: identity, bucket and truncate partitions on astring_viewcolumn, withbinary_viewand nested view columns alongside.test_append_view_types_to_partitioned_table: end-to-end append to a partitioned in-memory table, then read back.Both fail on
mainand pass with this change, on pyarrow 25.0.1 and on the minimum supported pyarrow 18.1.0.Are there any user-facing changes?
Yes. Appending, overwriting, and dynamically overwriting partitioned tables with Arrow view type columns now works where it used to raise.