Skip to content

[Python] ParquetWriter use_compliant_nested_type=True does not preserve ExtensionArray when reading back #31731

Description

@asfimport

I've been happily making ExtensionArrays, but recently noticed that they aren't preserved by round-trips through Parquet files when {}use_compliant_nested_type=True{}.

Consider this writer.py:

importjsonimportnumpyasnpimportpyarrowaspaimportpyarrow.parquetaspqclassAnnotatedType(pa.ExtensionType):
def__init__(self, storage_type, annotation):
self.annotation = annotationsuper().__init__(storage_type, "my:app")
def__arrow_ext_serialize__(self):
returnjson.dumps(self.annotation).encode()
@classmethoddef__arrow_ext_deserialize__(cls, storage_type, serialized):
annotation = json.loads(serialized.decode())
returncls(storage_type, annotation)
@propertydefnum_buffers(self):
returnself.storage_type.num_buffers@propertydefnum_fields(self):
returnself.storage_type.num_fieldspa.register_extension_type(AnnotatedType(pa.null(), None))
array = pa.Array.from_buffers(
AnnotatedType(pa.list_(pa.float64()), {"cool": "beans"}), 3, [None, pa.py_buffer(np.array([0, 3, 3, 5], np.int32))], children=[pa.array([1.1, 2.2, 3.3, 4.4, 5.5])],)table = pa.table({"": array})print(table)pq.write_table(table, "tmp.parquet", use_compliant_nested_type=True)

And this reader.py:

importjsonimportnumpyasnpimportpyarrowaspaimportpyarrow.parquetaspqclassAnnotatedType(pa.ExtensionType):
def__init__(self, storage_type, annotation):
self.annotation = annotationsuper().__init__(storage_type, "my:app")
def__arrow_ext_serialize__(self):
returnjson.dumps(self.annotation).encode()
@classmethoddef__arrow_ext_deserialize__(cls, storage_type, serialized):
annotation = json.loads(serialized.decode())
returncls(storage_type, annotation)
@propertydefnum_buffers(self):
returnself.storage_type.num_buffers@propertydefnum_fields(self):
returnself.storage_type.num_fieldspa.register_extension_type(AnnotatedType(pa.null(), None))
table = pq.read_table("tmp.parquet")
print(table)

(The AnnotatedType is the same; I wrote it twice for explicitness.)

When the writer.py has {}use_compliant_nested_type=False{}, the output is

% pythonwriter.pypyarrow.Table
: extension<my:app<AnnotatedType>>
----
: [[[1.1,2.2,3.3],[],[4.4,5.5]]]
% pythonreader.pypyarrow.Table
: extension<my:app<AnnotatedType>>
----
: [[[1.1,2.2,3.3],[],[4.4,5.5]]]

In other words, the AnnotatedType is preserved. When {}use_compliant_nested_type=True{}, however,

% rmtmp.parquetrm: removeregularfile'tmp.parquet'? y
% pythonwriter.pypyarrow.Table
: extension<my:app<AnnotatedType>>
----
: [[[1.1,2.2,3.3],[],[4.4,5.5]]]
% pythonreader.pypyarrow.Table
: list<element: double>
child0, element: double
----
: [[[1.1,2.2,3.3],[],[4.4,5.5]]]

The issue doesn't seem to be in the writing, but in the reading: regardless of whether use_compliant_nested_type is True or {}False{}, I can see the extension metadata in the Parquet → Arrow converted schema.

>>> importpyarrow.parquetaspq
>>> pq.ParquetFile("tmp.parquet").schema.to_arrow_schema()
: list<item: double>
child0, item: double
-- fieldmetadata --
ARROW:extension:metadata: '{"cool": "beans"}'ARROW:extension:name: 'my:app'

versus

>>> importpyarrow.parquetaspq
>>> pq.ParquetFile("tmp.parquet").schema.to_arrow_schema()
: list<element: double>
child0, element: double
-- fieldmetadata --
ARROW:extension:metadata: '{"cool": "beans"}'ARROW:extension:name: 'my:app'

Note that the first has "{}item: double{}" and the second has "{}element: double{}".

(I'm also rather surprised that use_compliant_nested_type=False is an option. Wouldn't you want the Parquet files to always be written with compliant lists? I noticed this when I was having trouble getting the data into BigQuery.)

Environment: pyarrow 7.0.0 installed via pip.
Reporter: Jim Pivarski / @jpivarski

Note: This issue was originally created as ARROW-16348. Please see the migration documentation for further details.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions