Skip to content

feat(parquet): support reading list columns as Arrow large_list - #714

Open
rahulsmahadev wants to merge 4 commits into
apache:mainfrom
rahulsmahadev:feat-parquet-large-list
Open

feat(parquet): support reading list columns as Arrow large_list#714
rahulsmahadev wants to merge 4 commits into
apache:mainfrom
rahulsmahadev:feat-parquet-large-list

Conversation

@rahulsmahadev

Copy link
Copy Markdown

Summary

Implements the remaining LargeListArray gaps from #502, following the design suggested by @wgtmac in #513:

  1. ValidateParquetSchemaEvolution now accepts LARGE_LIST wherever LIST is accepted, so schema projection works when the Arrow reader presents 64-bit offset list types.
  2. A new reader property read.arrow.use-large-list (default: false) configures the Parquet reader via ArrowReaderProperties::set_list_type(::arrow::Type::LARGE_LIST) to decode list columns as large_list.

Since ToArrowSchema builds the reader's output schema with 32-bit lists (and ProjectRecordBatch dispatches on the output schema type), enabling the property also rewrites list fields in the output Arrow schema to large_list so the projection layer takes the ProjectLargeListArray path added in #502. The rewrite is local to the Parquet reader to avoid changing the ToArrowSchema signature used across writers and manifest readers.

Closes #513

Changes

  • src/iceberg/parquet/parquet_schema_util.cc: accept LARGE_LIST for TypeId::kList in schema evolution validation.
  • src/iceberg/file_reader.h: add ReaderProperties::kArrowUseLargeList (read.arrow.use-large-list, default false), following the kBatchSize pattern.
  • src/iceberg/parquet/parquet_reader.cc: set ArrowReaderProperties::set_list_type when 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_list Arrow type validates against an Iceberg ListType.
  • ParquetSchemaProjectionTest.ProjectLargeListType: projection over a SchemaManifest built with set_list_type(LARGE_LIST) (the same path BuildProjection uses in the reader).
  • ParquetReaderTest.ReadListType: default behavior unchanged — list columns read as 32-bit offset list.
  • ParquetReaderTest.ReadListAsLargeList: with read.arrow.use-large-list=true, the output schema exposes large_list and values round-trip correctly (verified via array slices since JSON parsing creates regular ListArray).

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.

@rahulsmahadev

Copy link
Copy Markdown
Author

@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 ToArrowSchema, which uses 32-bit lists) also needed to be aligned so ProjectRecordBatch dispatches to the large_list path from #502. I kept that rewrite local to the Parquet reader to avoid changing the ToArrowSchema signature, but happy to take a different approach if you'd prefer.

@wgtmac

wgtmac commented Jun 15, 2026

Copy link
Copy Markdown
Member

Thanks for improving this, @rahulsmahadev! I think the long-term shape is to make this output-schema driven, ideally allowing callers to choose list vs large_list per projected column. Arrow’s Parquet reader only exposes a global set_list_type today, so keeping a global flag for this PR seems reasonable.

One API concern: since this option lives in generic ReaderProperties, it reads as format-independent. Either other readers such as Avro should honor it too, or the option should be clearly scoped/documented as Parquet-only.

One thing that is worth noting: when read.arrow.use-large-list is enabled, the reader always rewrites the output schema to large_list, but Arrow ignores set_list_type(LARGE_LIST) when the Parquet file contains serialized ARROW:schema metadata. In that case the actual batch can still contain ListArray, while ProjectRecordBatch dispatches as LargeListArray, causing a bad cast/crash. Please base the output schema on the actual reader schema or add a guard, and cover this with an ARROW:schema regression test.

}
};

std::shared_ptr<::arrow::Field> UseLargeListField(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

add comment:

Suggested change
std::shared_ptr<::arrow::Field> UseLargeListField(
// forward declaration to unblock cycle dependence.
std::shared_ptr<::arrow::Field> UseLargeListField(

Comment thread src/iceberg/parquet/parquet_reader.cc Outdated
Comment on lines +260 to +264
::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));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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;
}

@rahulsmahadev

Copy link
Copy Markdown
Author

@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
@rahulsmahadev
rahulsmahadev force-pushed the feat-parquet-large-list branch from 6773aa9 to af0c94f Compare August 5, 2026 06:38
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.
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.

Enable LargeListArray support in Parquet reader schema validation

3 participants