Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arrow: Infer the types when reading #1669

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open

Conversation

Fokko
Copy link
Contributor

@Fokko Fokko commented Feb 16, 2025

Time to give this another go 😆

When reading a Parquet file using PyArrow, there is some metadata stored in the Parquet file to either make it a large type (eg large_string, or a normal type (string). The difference is that the large types use a 64 bit offset to encode their arrays. This is not always needed, and we can could first check all the in the types of which it is stored, and let PyArrow decide here:

result = pa.concat_tables(tables, promote_options="permissive")

In PyArrow today we just bump everything to a large type, which might lead to additional memory consumption because it allocates an int64 array to allocate the offsets, instead of an int32.

I thought we would be good to go for this now with the new lower bound of PyArrow to 17. But, it looks like we still have to wait for Arrow 18 to fix the issue with the date types:

apache/arrow#43183

Fixes: #1049

When reading a Parquet file using PyArrow, there is some metadata
stored in the Parquet file to either make it a large type (eg
`large_string`, or a normal type (`string`). The difference is that
the large types use a 64 bit offset to encode their arrays.
This is not always needed, and we can could first check all the
in the types of which it is stored, and let PyArrow decide here:

https://github.com/apache/iceberg-python/blob/300b8405a0fe7d0111321e5644d704026af9266b/pyiceberg/io/pyarrow.py#L1579

In PyArrow today we just bump everything to a large type, which
might lead to additional memory consumption because it allocates
a int64 array to allocate the offsets, instead of an int32.

I thought we would be good to go for this now with the new lower
bound of PyArrow to 17. But, it looks like we still have to wait
for Arrow 18 to fix the issue with the `date` types:

apache/arrow#43183

Fixes: apache#1049
@@ -1750,7 +1750,7 @@ def to_arrow_batch_reader(self) -> pa.RecordBatchReader:
return pa.RecordBatchReader.from_batches(
target_schema,
batches,
)
).cast(target_schema)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will still return large types if you stream the batches because we don't want to fetch all the schemas upfront.

Comment on lines +1571 to +1572
if property_as_bool(self._io.properties, PYARROW_USE_LARGE_TYPES_ON_READ, False):
result = result.cast(arrow_schema)
Copy link
Contributor Author

@Fokko Fokko Feb 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left this in, but I would be leaning toward deprecating this, since I don't think we want to trouble the user. I think it should be an implementation detail based on how large the buffers are.

@Fokko
Copy link
Contributor Author

Fokko commented Feb 18, 2025

@sungwy Thoughts? :D

Copy link
Collaborator

@sungwy sungwy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Fokko - thank you for pinging me for review! The change looks good to me, but I have a reservation about introducing this change without a deprecation warning.

Firstly, without the PyIceberg code base having a properly defined list of public classes, we assume all our classes to be public facing unless they start with an underscore. I'd argue that removing an input parameter to the ArrowProjectionVisitor __init__ method is an API change.

Secondly, changing the default value of PYARROW_USE_LARGE_TYPES_ON_READ to True for to_table method also seems like a breaking change for users reading Iceberg tables through PyIceberg. their large_string columns will change to a string column on upgrade without a warning.

Would it make sense to introduce this change in two stages:

  1. First by introducing a new config variable like: PYICEBERG_INFER_LARGE_TYPES_ON_READ and set it to False on default, and raise a deprecation warning when the flag is set to False?
  2. Then remove PYICEBERG_INFER_LARGE_TYPES_ON_READ and PYARROW_USE_LARGE_TYPES_ON_READ in the next major version?


def __init__(
self,
file_schema: Schema,
downcast_ns_timestamp_to_us: bool = False,
include_field_ids: bool = False,
use_large_types: bool = True,
Copy link
Collaborator

@sungwy sungwy Feb 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've always dreaded the process of updating our code base in these internal classes and functions because we do not yet have a properly defined list of public classes 😞

Would this change require a deprecation notice first?


result = pa.concat_tables(tables, promote_options="permissive")

if property_as_bool(self._io.properties, PYARROW_USE_LARGE_TYPES_ON_READ, False):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we update this to align with the current default value?

Suggested change
if property_as_bool(self._io.properties, PYARROW_USE_LARGE_TYPES_ON_READ, False):
if property_as_bool(self._io.properties, PYARROW_USE_LARGE_TYPES_ON_READ, True):

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[feat] push down schema casting to the record batch level
2 participants