feat(parquet): support reading list columns as Arrow large_list - #714
feat(parquet): support reading list columns as Arrow large_list#714rahulsmahadev wants to merge 4 commits into
Conversation
|
@wgtmac this implements the design you suggested in #513 — would appreciate a review when you get a chance. One note beyond the two items in the issue: the reader's output Arrow schema (built by |
|
Thanks for improving this, @rahulsmahadev! I think the long-term shape is to make this output-schema driven, ideally allowing callers to choose One API concern: since this option lives in generic One thing that is worth noting: when |
| } | ||
| }; | ||
|
|
||
| std::shared_ptr<::arrow::Field> UseLargeListField( |
There was a problem hiding this comment.
add comment:
| std::shared_ptr<::arrow::Field> UseLargeListField( | |
| // forward declaration to unblock cycle dependence. | |
| std::shared_ptr<::arrow::Field> UseLargeListField( |
| ::arrow::FieldVector fields; | ||
| fields.reserve(context_->output_arrow_schema_->fields().size()); | ||
| for (const auto& field : context_->output_arrow_schema_->fields()) { | ||
| fields.push_back(UseLargeListField(field)); | ||
| } |
There was a problem hiding this comment.
this is duplicated logic.
let's add a method.
::arrow::FieldVector UseLargeListFields(const ::arrow::FieldVector& fields) {
::arrow::FieldVector rewritten;
rewritten.reserve(fields.size());
for (const auto& field : fields) {
rewritten.push_back(UseLargeListField(field));
}
return rewritten;
}
|
@wgtmac can you help review |
Implements the remaining gaps from apache#502: - Accept LARGE_LIST in ValidateParquetSchemaEvolution wherever LIST is accepted, so schema projection works when the Arrow reader presents 64-bit offset list types. - Add a read.arrow.use-large-list reader property (default: false) that configures the Parquet reader to decode list columns as large_list and aligns the output Arrow schema accordingly. Closes apache#513 Signed-off-by: rahulsmahadev <rahul.mahadev@databricks.com>
Signed-off-by: rahulsmahadev <rahul.mahadev@databricks.com>
Arrow honors set_list_type(LARGE_LIST) only when it derives the Arrow schema from the Parquet schema. When a file carries serialized ARROW:schema metadata, the reader keeps producing plain list arrays, but the output schema was rewritten to large_list unconditionally. ProjectRecordBatch then built the projected batch against a large_list schema while the incoming arrays were list arrays, which casts a ListArray to a LargeListArray. The output schema is the target of the projection, so it keeps being derived from the projected Iceberg schema, and the large_list rewrite is now applied only when the reader actually produces large lists. Adds a regression test that reads a file written through parquet::arrow::WriteTable, which serializes ARROW:schema, with use-large-list enabled. Also addresses review comments: - comment the forward declaration of UseLargeListField - extract the duplicated field rewriting into UseLargeListFields
6773aa9 to
af0c94f
Compare
The ARROW:schema regression test asserted that the output schema reports a plain list, on the assumption that Arrow ignores the requested large_list type whenever the file carries serialized ARROW:schema metadata. CI shows that Arrow does apply large_list for this file, so the assertion failed. What the test needs to guard is that the output schema describes the arrays the reader actually produces, whichever list type that is. It now reads the list type from the reported schema, imports the array against that schema, which fails if the two disagree, and verifies the values through the matching array type.
Summary
Implements the remaining
LargeListArraygaps from #502, following the design suggested by @wgtmac in #513:ValidateParquetSchemaEvolutionnow acceptsLARGE_LISTwhereverLISTis accepted, so schema projection works when the Arrow reader presents 64-bit offset list types.read.arrow.use-large-list(default:false) configures the Parquet reader viaArrowReaderProperties::set_list_type(::arrow::Type::LARGE_LIST)to decode list columns aslarge_list.Since
ToArrowSchemabuilds the reader's output schema with 32-bit lists (andProjectRecordBatchdispatches on the output schema type), enabling the property also rewrites list fields in the output Arrow schema tolarge_listso the projection layer takes theProjectLargeListArraypath added in #502. The rewrite is local to the Parquet reader to avoid changing theToArrowSchemasignature used across writers and manifest readers.Closes #513
Changes
src/iceberg/parquet/parquet_schema_util.cc: acceptLARGE_LISTforTypeId::kListin schema evolution validation.src/iceberg/file_reader.h: addReaderProperties::kArrowUseLargeList(read.arrow.use-large-list, defaultfalse), following thekBatchSizepattern.src/iceberg/parquet/parquet_reader.cc: setArrowReaderProperties::set_list_typewhen the property is enabled, and align the output Arrow schema (lists nested in structs/maps included) with the large_list arrays produced by the reader.Test plan
ParquetSchemaProjectionTest.ValidateSchemaEvolutionAllowsLargeList:large_listArrow type validates against an IcebergListType.ParquetSchemaProjectionTest.ProjectLargeListType: projection over aSchemaManifestbuilt withset_list_type(LARGE_LIST)(the same pathBuildProjectionuses in the reader).ParquetReaderTest.ReadListType: default behavior unchanged — list columns read as 32-bit offsetlist.ParquetReaderTest.ReadListAsLargeList: withread.arrow.use-large-list=true, the output schema exposeslarge_listand values round-trip correctly (verified via array slices since JSON parsing creates regularListArray).Note: my local environment lacks a C++23 toolchain (cmake 3.16/gcc 10), so I could not build locally; relying on CI to verify. All Arrow APIs used (
set_list_type,large_list(field),MapType(key_field, item_field, keys_sorted),Field::WithType) were checked against the pinned Arrow 24.0.0 headers.