Select Parquet columns by field ID - #22955
Conversation
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds ChangesParquet column selection by field ID
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cpp/src/io/parquet/expression_transform_helpers.cpp`:
- Around line 277-281: The validation using std::cmp_less for selected_col_idx
only checks the upper bound against root.children_idx.size() but does not
validate that the index is non-negative. A negative selected_col_idx would
bypass this check and cause undefined behavior when used to index into
root.children_idx on the following line. Add an additional validation check to
ensure selected_col_idx is greater than or equal to zero, either as a separate
CUDF_EXPECTS call or by combining it with the existing upper bound check using a
logical AND condition.
In `@cpp/src/io/parquet/reader_impl_helpers.cpp`:
- Around line 1924-1930: The field-ID based lookup is currently only applied
when col_name_info has explicit child paths, but the all-children branch that
handles non-leaf field ID selection still uses ordinal-based pairing for
descendants. Locate the branch that handles the case where a non-leaf field is
selected without explicit child paths (the all-children case), and modify it to
use field-ID lookup similar to the code shown in the diff. Specifically, replace
the ordinal-based child pairing logic with calls to
find_schema_child_for_mapping (instead of just find_schema_child) when iterating
through all children of the selected field, ensuring that nested children are
matched by field ID across sources rather than by position.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: c661b3f7-43fd-4b6c-870a-17ce7cc8efd7
📒 Files selected for processing (14)
cpp/include/cudf/io/parquet.hppcpp/src/io/parquet/column_path_helpers.cppcpp/src/io/parquet/column_path_helpers.hppcpp/src/io/parquet/experimental/hybrid_scan_helpers.cppcpp/src/io/parquet/experimental/hybrid_scan_helpers.hppcpp/src/io/parquet/experimental/hybrid_scan_impl.cppcpp/src/io/parquet/expression_transform_helpers.cppcpp/src/io/parquet/expression_transform_helpers.hppcpp/src/io/parquet/reader_impl.cppcpp/src/io/parquet/reader_impl_helpers.cppcpp/src/io/parquet/reader_impl_helpers.hppcpp/tests/io/parquet_common.cppcpp/tests/io/parquet_common.hppcpp/tests/io/parquet_reader_test.cpp
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cpp/tests/io/parquet_reader_test.cpp`:
- Around line 641-645: The regression test in the parquet_reader_test.cpp file
is not exercising child field-ID selection as intended because
column_field_ids({1}) only selects the top-level record struct. To fix this,
modify the column_field_ids call in the parquet_reader_options builder to select
a child field ID (such as {2} or {3} representing child fields like x or y)
instead of the top-level field, and then add assertions that verify the
projected nested output shape is correct. This ensures the test properly catches
bugs in mismatched-schema child lookup by field ID.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 3eba06e6-f115-4ed3-afb5-611e4e689556
📒 Files selected for processing (3)
cpp/src/io/parquet/expression_transform_helpers.cppcpp/src/io/parquet/reader_impl_helpers.cppcpp/tests/io/parquet_reader_test.cpp
🚧 Files skipped from review as they are similar to previous changes (2)
- cpp/src/io/parquet/expression_transform_helpers.cpp
- cpp/src/io/parquet/reader_impl_helpers.cpp
| {col_idx, normalize_column_path(schema_tree[schema_idx].name, case_sensitive_names)}); | ||
| }); | ||
| } | ||
| std::transform( |
There was a problem hiding this comment.
Mostly whitespace here (try hiding it in your view). The only interesting part is under else if (selected_column_field_ids.has_value()) { block.
| */ | ||
| [[nodiscard]] auto const& get_column_indices() const { return _column_indices; } | ||
|
|
||
| /** |
There was a problem hiding this comment.
Pretty standard setters and getters
| decimal_type_id, | ||
| case_sensitive_names); | ||
| case_sensitive_names, | ||
| match_schema_by_field_id); |
There was a problem hiding this comment.
Just plumbed in a new boolean field
There was a problem hiding this comment.
these are mutually exclusive right? should you instead switch to an enum to reduce the number of arguments? the api is experimental after all.
There was a problem hiding this comment.
these are mutually exclusive right?
Yes
should you instead switch to an enum to reduce the number of arguments? the api is experimental after all.
We are calling the base reader's select_columns API (being updated to take in another bool here).
There was a problem hiding this comment.
sure but can we update that API also to reduce argument bloat everywhere
| cudf::host_span<cudf::host_span<uint8_t const> const> footer_bytes, | ||
| parquet_reader_options const& options) | ||
| { | ||
| auto const has_cols_from_mismatched_srcs = |
There was a problem hiding this comment.
Separate out this logic: We can have mismatched columns if allowed AND selecting columns by names or field IDs
| hybrid_scan_reader_impl::hybrid_scan_reader_impl( | ||
| cudf::host_span<FileMetaData const> parquet_metadatas, parquet_reader_options const& options) | ||
| { | ||
| auto const has_cols_from_mismatched_srcs = |
|
|
||
| namespace cudf::io::parquet::detail { | ||
|
|
||
| std::string column_path_from_index(std::span<SchemaElement const> schema_tree, int schema_idx) |
There was a problem hiding this comment.
Given a ColumnChunk field ID, keep going to its parent until root and then construct a dot (.) separated string path
| for (std::size_t i = 0; i < column_names.size(); ++i) { | ||
| md.column_metadata[i].set_name(column_names[i]); | ||
| } | ||
| for (std::size_t i = 0; i < field_ids.size(); ++i) { |
There was a problem hiding this comment.
Allow setting field_ids in the written parquet files in tests
| find_schema_child(src_schema_elem, child_col_name_info.name), | ||
| find_schema_child(dst_schema_elem, child_col_name_info.name, pfm_idx), | ||
| pfm_idx); | ||
| auto const src_child_idx = find_schema_child(src_schema_elem, child_col_name_info.name); |
There was a problem hiding this comment.
For structs, make sure all children (not necessarily arranged in the same order though) have the same field ID as well.
| : -1; | ||
| }; | ||
|
|
||
| auto const find_schema_child_for_mapping = [&](SchemaElement const& src_schema_elem, |
There was a problem hiding this comment.
Either calls find_schema_child (by name) or find_schema_child_by_field_id
| CUDF_TEST_EXPECT_COLUMNS_EQUAL(result.tbl->view().column(3), c); | ||
| } | ||
|
|
||
| { |
There was a problem hiding this comment.
Modify existing column selection tests here to test column selection with and without filters by field ID
0914161 to
fe2485d
Compare
| CUDF_EXPECTS( | ||
| not(selected_column_names.has_value() and selected_column_indices.has_value()), | ||
| "Parquet reader encountered column selection by both names and indices simultaneously"); | ||
| CUDF_EXPECTS(static_cast<int>(selected_column_names.has_value()) + |
There was a problem hiding this comment.
I feel like we should not be doing this. The options object has the invariant that only one of these is set.
|
/merge |
Follow up ##22955 This PR adds python bindings for Parquet column selection by field ID Authors: - Muhammad Haseeb (https://github.com/mhaseeb123) Approvers: - Matthew Murray (https://github.com/Matt711) URL: #22956
Description
Contributes to #22849
This PR enables the parquet readers to select columns using parquet field ID (needed for Iceberg) where column names across table files may vary.
Checklist