Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
08f1e36
Select Parquet columns by field ID
mhaseeb123 Jun 24, 2026
5781078
Merge branch 'main' into fea/select-pq-cols-by-field-id
mhaseeb123 Jun 24, 2026
4241c2d
Apply suggestion from coderabbit
mhaseeb123 Jun 24, 2026
4b99d07
Minor
mhaseeb123 Jun 24, 2026
43235a3
Style
mhaseeb123 Jun 24, 2026
2d26e65
Minor bug fix
mhaseeb123 Jun 24, 2026
3cc2e46
Merge branch 'main' into fea/select-pq-cols-by-field-id
mhaseeb123 Jun 24, 2026
5048a45
Merge branch 'main' into fea/select-pq-cols-by-field-id
mhaseeb123 Jun 24, 2026
d51c620
Apply partial suggestions
mhaseeb123 Jun 25, 2026
09e8735
Apply suggestions
mhaseeb123 Jun 25, 2026
b006c62
Merge branch 'main' into fea/select-pq-cols-by-field-id
mhaseeb123 Jun 26, 2026
8d95803
style
mhaseeb123 Jun 26, 2026
cea7b9f
Merge branch 'main' into fea/select-pq-cols-by-field-id
mhaseeb123 Jun 26, 2026
12eedd9
Merge branch 'main' into fea/select-pq-cols-by-field-id
mhaseeb123 Jun 27, 2026
04a2527
Merge branch 'main' into fea/select-pq-cols-by-field-id
vyasr Jun 30, 2026
fe2485d
Merge branch 'main' into fea/select-pq-cols-by-field-id
mhaseeb123 Jun 30, 2026
545b82f
Merge branch 'main' into fea/select-pq-cols-by-field-id
mhaseeb123 Jul 1, 2026
3dfb09f
Address reviews
mhaseeb123 Jul 1, 2026
8417b0e
Merge branch 'main' into fea/select-pq-cols-by-field-id
mhaseeb123 Jul 1, 2026
8073240
style
mhaseeb123 Jul 2, 2026
f920a00
Minor
mhaseeb123 Jul 2, 2026
12cf311
Merge branch 'main' into fea/select-pq-cols-by-field-id
mhaseeb123 Jul 2, 2026
1335b4a
Merge branch 'main' into fea/select-pq-cols-by-field-id
mhaseeb123 Jul 9, 2026
e66174a
Address comments
mhaseeb123 Jul 10, 2026
a18925b
Merge branch 'main' into fea/select-pq-cols-by-field-id
mhaseeb123 Jul 10, 2026
86a4b48
Merge branch 'main' into fea/select-pq-cols-by-field-id
mhaseeb123 Jul 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions cpp/include/cudf/io/parquet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,14 @@ class parquet_reader_options_builder;
class parquet_reader_options {
source_info _source;

// Column selection options. At most one of these may be set at a time.

// Path in schema of column names to read; `nullopt` is all
std::optional<std::vector<std::string>> _column_names;
// Indices of top-level columns to read; `nullopt` is all (cannot be used alongside
// `_column_names`)
// Indices of top-level columns to read; `nullopt` is all
std::optional<std::vector<cudf::size_type>> _column_indices;
// Parquet field IDs of columns/fields to read; `nullopt` is all
std::optional<std::vector<int32_t>> _column_field_ids;

// List of individual row groups to read (ignored if empty)
std::vector<std::vector<size_type>> _row_groups;
Expand Down Expand Up @@ -258,6 +261,13 @@ class parquet_reader_options {
*/
[[nodiscard]] auto const& get_column_indices() const { return _column_indices; }

/**

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Pretty standard setters and getters

* @brief Returns Parquet field IDs of columns/fields to be read, if set.
*
* @return Parquet field IDs of columns/fields to be read; `nullopt` if the option is not set
*/
[[nodiscard]] auto const& get_column_field_ids() const { return _column_field_ids; }

/**
* @brief Returns list of individual row groups to be read.
*
Expand Down Expand Up @@ -386,6 +396,8 @@ class parquet_reader_options {
{
CUDF_EXPECTS(not _column_indices.has_value(),
"Cannot select columns by indices and names simultaneously");
CUDF_EXPECTS(not _column_field_ids.has_value(),
"Cannot select columns by field IDs and names simultaneously");
_column_names = std::move(column_names);
}

Expand All @@ -404,9 +416,26 @@ class parquet_reader_options {
{
CUDF_EXPECTS(not _column_names.has_value(),
"Cannot select columns by indices and names simultaneously");
CUDF_EXPECTS(not _column_field_ids.has_value(),
"Cannot select columns by field IDs and indices simultaneously");
_column_indices = std::move(col_indices);
}

/**
* @brief Sets the Parquet field IDs of columns/fields to be read from all input sources.
*
* @param column_field_ids A vector of Parquet field IDs to attempt to read from each input
* source.
*/
void set_column_field_ids(std::vector<int32_t> column_field_ids)
{
CUDF_EXPECTS(not _column_names.has_value(),
"Cannot select columns by field IDs and names simultaneously");
CUDF_EXPECTS(not _column_indices.has_value(),
"Cannot select columns by field IDs and indices simultaneously");
_column_field_ids = std::move(column_field_ids);
}

/**
* @brief Specifies which row groups to read from each input source.
*
Expand Down Expand Up @@ -647,6 +676,19 @@ class parquet_reader_options_builder {
return *this;
}

/**
* @brief Sets the Parquet field IDs of columns/fields to be read from all input sources.
*
* @param column_field_ids A vector of Parquet field IDs to attempt to read from each input
* source.
* @return this for chaining
*/
parquet_reader_options_builder& column_field_ids(std::vector<int32_t> column_field_ids)
{
options.set_column_field_ids(std::move(column_field_ids));
return *this;
}

/**
* @copydoc parquet_reader_options::set_row_groups
* @return this for chaining
Expand Down
20 changes: 19 additions & 1 deletion cpp/src/io/parquet/column_path_helpers.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,37 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION.
* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#include "column_path_helpers.hpp"

#include <cudf/io/parquet_schema.hpp>

#include <algorithm>
#include <cctype>
#include <cstddef>
#include <functional>
#include <numeric>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

namespace cudf::io::parquet::detail {

std::string column_path_from_index(std::span<SchemaElement const> schema_tree, int schema_idx)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Given a ColumnChunk field ID, keep going to its parent until root and then construct a dot (.) separated string path

{
std::vector<std::string> path;
for (auto idx = schema_idx; idx > 0; idx = schema_tree[idx].parent_idx) {
path.push_back(schema_tree[idx].name);
}

return std::accumulate(
path.rbegin() + 1, path.rend(), path.back(), [](auto path_so_far, auto const& elem_name) {
return std::move(path_so_far) + "." + elem_name;
});
}

std::string normalize_column_path(std::string_view col_path, bool case_sensitive_names)
{
if (case_sensitive_names) { return std::string{col_path}; }
Expand Down
15 changes: 14 additions & 1 deletion cpp/src/io/parquet/column_path_helpers.hpp
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION.
* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#include <cudf/io/parquet_schema.hpp>

#include <cstddef>
#include <span>
#include <string>
#include <string_view>
#include <unordered_map>
#include <unordered_set>

namespace cudf::io::parquet::detail {

/**
* @brief Gets the dot-separated path for a schema element.
*
* @param schema_tree The schema tree describing the file structure
* @param schema_idx Index of the schema element
* @return Dot-separated schema path from the root child to the schema element
*/
[[nodiscard]] std::string column_path_from_index(std::span<SchemaElement const> schema_tree,
int schema_idx);

/**
* @brief Returns a normalized (lowercased) column name or path when case-insensitive matching is
* enabled
Expand Down
38 changes: 6 additions & 32 deletions cpp/src/io/parquet/experimental/hybrid_scan_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,24 +266,12 @@ std::tuple<std::vector<input_column_info>,
aggregate_reader_metadata::select_payload_columns(
std::optional<std::vector<std::string>> const& payload_column_names,
std::optional<std::vector<std::string>> const& filter_column_names,
bool include_index,
bool strings_to_categorical,
bool ignore_missing_columns,
type_id timestamp_type_id,
type_id decimal_type_id,
bool case_sensitive_names)
parquet::detail::column_selection_options const& selection_options)
{
// If neither payload nor filter columns are specified, select all columns
if (not payload_column_names.has_value() and not filter_column_names.has_value()) {
// Call the base `select_columns()` method without specifying any columns
return select_columns({},
{},
include_index,
strings_to_categorical,
ignore_missing_columns,
timestamp_type_id,
decimal_type_id,
case_sensitive_names);
return select_columns({}, {}, selection_options);
}

std::vector<std::string> valid_payload_columns;
Expand All @@ -302,7 +290,7 @@ aggregate_reader_metadata::select_payload_columns(
// Remove filter columns from the provided payload column names
if (filter_column_names.has_value() and not filter_column_names->empty()) {
auto const filter_columns_set =
construct_filter_columns_set(*filter_column_names, case_sensitive_names);
construct_filter_columns_set(*filter_column_names, selection_options.case_sensitive_names);
// Remove a payload column name if it is also present in the hash set
valid_payload_columns.erase(
std::remove_if(valid_payload_columns.begin(),
Expand All @@ -311,20 +299,13 @@ aggregate_reader_metadata::select_payload_columns(
valid_payload_columns.end());
}
// Call the base `select_columns()` method with valid payload columns
return select_columns(valid_payload_columns,
{},
include_index,
strings_to_categorical,
ignore_missing_columns,
timestamp_type_id,
decimal_type_id,
case_sensitive_names);
return select_columns(valid_payload_columns, {}, selection_options);
}

// Else if only filter columns are specified, select all columns that do not appear in the
// filter expression
auto const filter_columns_set =
construct_filter_columns_set(*filter_column_names, case_sensitive_names);
construct_filter_columns_set(*filter_column_names, selection_options.case_sensitive_names);

std::function<void(std::string, int)> add_column_path = [&](std::string path_till_now,
int schema_idx) {
Expand All @@ -341,14 +322,7 @@ aggregate_reader_metadata::select_payload_columns(
}
}

return select_columns(valid_payload_columns,
{},
include_index,
strings_to_categorical,
ignore_missing_columns,
timestamp_type_id,
decimal_type_id,
case_sensitive_names);
return select_columns(valid_payload_columns, {}, selection_options);
}

std::vector<std::vector<cudf::size_type>>
Expand Down
14 changes: 2 additions & 12 deletions cpp/src/io/parquet/experimental/hybrid_scan_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,7 @@ class aggregate_reader_metadata : public aggregate_reader_metadata_base {
*
* @param payload_column_names List of paths of select payload column names, if any
* @param filter_column_names List of paths of column names present only in filter, if any
* @param include_index Whether to always include the PANDAS index column(s)
* @param strings_to_categorical Type conversion parameter
* @param ignore_missing_columns Whether to ignore non-existent columns
* @param timestamp_type_id Type conversion parameter
* @param decimal_type_id Type conversion parameter
* @param case_sensitive_names Boolean indicating if column names are case sensitive
* @param selection_options Bundled column selection options
*
* @return input column information, output column buffers, list of output column schema
* indices
Expand All @@ -172,12 +167,7 @@ class aggregate_reader_metadata : public aggregate_reader_metadata_base {
tuple<std::vector<input_column_info>, std::vector<inline_column_buffer>, std::vector<size_type>>
select_payload_columns(std::optional<std::vector<std::string>> const& payload_column_names,
std::optional<std::vector<std::string>> const& filter_column_names,
bool include_index,
bool strings_to_categorical,
bool ignore_missing_columns,
type_id timestamp_type_id,
type_id decimal_type_id,
bool case_sensitive_names);
parquet::detail::column_selection_options const& selection_options);

/**
* @brief Filters row groups such that only the row groups that start within the byte range
Expand Down
Loading
Loading