Repository navigation
[DNM] Add initial tests for Parquet to cuDF dictionary transcode #21728
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
mhaseeb123
wants to merge
3
commits into
NVIDIA:main
from
mhaseeb123:fea/test-pq-reader-dict-transcode
Closed
Changes from 2 commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,159 @@ | ||
| /* | ||
| * SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION. | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| #include "parquet_common.hpp" | ||
|
|
||
| #include <cudf_test/base_fixture.hpp> | ||
| #include <cudf_test/column_utilities.hpp> | ||
| #include <cudf_test/column_wrapper.hpp> | ||
| #include <cudf_test/type_lists.hpp> | ||
|
|
||
| #include <cudf/dictionary/dictionary_column_view.hpp> | ||
| #include <cudf/dictionary/encode.hpp> | ||
| #include <cudf/io/parquet.hpp> | ||
| #include <cudf/table/table_view.hpp> | ||
|
|
||
| #include <random> | ||
| #include <vector> | ||
|
|
||
| namespace { | ||
|
|
||
| constexpr cudf::size_type num_rows = 5000; | ||
| constexpr cudf::size_type cardinality = num_rows / 10; | ||
| constexpr cudf::size_type row_group_size = 1000; | ||
| constexpr unsigned int seed = 0xcece; | ||
| constexpr double null_probability = 0.1; | ||
|
|
||
| template <typename T> | ||
| cudf::test::fixed_width_column_wrapper<T, int32_t> column_low_cardinality() | ||
| requires(not std::is_same_v<T, cudf::string_view>) | ||
| { | ||
| std::mt19937 engine(seed); | ||
| std::uniform_int_distribution<int32_t> value_dist(0, cardinality - 1); | ||
| std::bernoulli_distribution null_dist(null_probability); | ||
|
|
||
| std::vector<int32_t> values(num_rows); | ||
| std::vector<bool> valids(num_rows); | ||
| for (cudf::size_type i = 0; i < num_rows; ++i) { | ||
| values[i] = value_dist(engine); | ||
| valids[i] = not null_dist(engine); | ||
| } | ||
|
|
||
| return cudf::test::fixed_width_column_wrapper<T, int32_t>( | ||
| values.begin(), values.end(), valids.begin()); | ||
| } | ||
|
|
||
| template <typename T> | ||
| cudf::test::strings_column_wrapper column_low_cardinality() | ||
| requires(std::is_same_v<T, cudf::string_view>) | ||
| { | ||
| std::mt19937 engine(seed); | ||
| std::uniform_int_distribution<int> value_dist(0, cardinality - 1); | ||
| std::bernoulli_distribution null_dist(null_probability); | ||
|
|
||
| std::vector<std::string> strings(num_rows); | ||
| std::vector<bool> valids(num_rows); | ||
| for (cudf::size_type i = 0; i < num_rows; ++i) { | ||
| strings[i] = "str_" + std::to_string(value_dist(engine)); | ||
| valids[i] = not null_dist(engine); | ||
| } | ||
|
|
||
| return cudf::test::strings_column_wrapper(strings.begin(), strings.end(), valids.begin()); | ||
| } | ||
|
|
||
| void write_parquet(cudf::table_view const& input, std::string const& filepath) | ||
| { | ||
| auto const options = | ||
| cudf::io::chunked_parquet_writer_options::builder(cudf::io::sink_info{filepath}) | ||
| .dictionary_policy(cudf::io::dictionary_policy::ALWAYS) | ||
| .compression(cudf::io::compression_type::NONE) | ||
| .stats_level(cudf::io::statistics_freq::STATISTICS_COLUMN) | ||
| .build(); | ||
|
|
||
| cudf::io::chunked_parquet_writer writer(options); | ||
| for (auto offset = 0; offset < input.num_rows(); offset += row_group_size) { | ||
| auto const length = std::min(row_group_size, input.num_rows() - offset); | ||
| auto const chunk = cudf::slice(input, {offset, offset + length}); | ||
| writer.write(chunk.front()); | ||
| } | ||
| writer.close(); | ||
| } | ||
|
|
||
| cudf::io::table_with_metadata read_parquet(std::string const& filepath) | ||
| { | ||
| auto const read_opts = | ||
| cudf::io::parquet_reader_options::builder(cudf::io::source_info{filepath}).build(); | ||
| return cudf::io::read_parquet(read_opts); | ||
| } | ||
|
|
||
| } // namespace | ||
|
|
||
| // TODO(mh): Temporarily only using integral and string types. Set this to the list of types in | ||
| // `hybrid_scan_filters_test.cpp` when we're ready | ||
| using DictionaryTestTypes = | ||
| cudf::test::Concat<cudf::test::IntegralTypesNotBool, cudf::test::StringTypes>; | ||
|
|
||
| template <typename T> | ||
| struct ParquetDictDecodeTest : public cudf::test::BaseFixture {}; | ||
|
|
||
| TYPED_TEST_SUITE(ParquetDictDecodeTest, DictionaryTestTypes); | ||
|
|
||
| TYPED_TEST(ParquetDictDecodeTest, DictDecodeParquet) | ||
| { | ||
| using T = TypeParam; | ||
|
|
||
| // Generate low cardinality data | ||
| auto input_col = column_low_cardinality<T>(); | ||
|
|
||
| // Write parquet | ||
| auto const input_tbl = cudf::table_view{{input_col}}; | ||
| auto const filepath = temp_env->get_temp_filepath("DictDecodeParquet.parquet"); | ||
| write_parquet(input_tbl, filepath); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Parquet file will have 1 col x 5000 rows of low cardinality (500) data for dictionary encoding. Shape: 5 row groups (each with 1000 rows) |
||
|
|
||
| // Dictionary encode and decode input column | ||
| auto const dict_input = cudf::dictionary::encode(input_col); | ||
| auto const dict_input_view = cudf::dictionary_column_view(dict_input->view()); | ||
| auto const decoded_input = cudf::dictionary::decode(dict_input_view); | ||
|
|
||
| #if 1 | ||
| // Bret's tests: Set is_bret_testing = true in `src/io/parquet/reader_impl.cpp` | ||
| { | ||
| // Read parquet into dictionary encoded cudf column | ||
| auto const read_table = read_parquet(filepath).tbl; | ||
| EXPECT_EQ(read_table->num_rows(), num_rows); | ||
| EXPECT_EQ(read_table->num_columns(), 1); | ||
|
|
||
| // Decode the read dictionary column | ||
| cudf::dictionary_column_view dict_read_view(read_table->view().column(0)); | ||
| auto const decoded_read = cudf::dictionary::decode(dict_read_view); | ||
|
|
||
| // Compare | ||
| CUDF_TEST_EXPECT_COLUMNS_EQUAL(input_col, decoded_read->view()); | ||
| CUDF_TEST_EXPECT_COLUMNS_EQUAL(decoded_input->view(), decoded_read->view()); | ||
| } | ||
| #else | ||
| // Set is_bret_testing = false in `src/io/parquet/reader_impl.cpp` | ||
| { | ||
| // Read parquet into standard cudf column | ||
| auto const read_table = read_parquet(filepath).tbl; | ||
| EXPECT_EQ(read_table->num_rows(), num_rows); | ||
| EXPECT_EQ(read_table->num_columns(), 1); | ||
|
|
||
| // Compare input and read columns | ||
| auto const read_col = read_table->view().column(0); | ||
| CUDF_TEST_EXPECT_COLUMNS_EQUAL(input_col, read_col); | ||
|
|
||
| // Dictionary encode and decode read column | ||
| auto const dict_read = cudf::dictionary::encode(read_col); | ||
| cudf::dictionary_column_view dict_read_view(dict_read->view()); | ||
| auto const decoded_read = cudf::dictionary::decode(dict_read_view); | ||
|
|
||
| // Compare | ||
| CUDF_TEST_EXPECT_COLUMNS_EQUAL(read_col, decoded_input->view()); | ||
| CUDF_TEST_EXPECT_COLUMNS_EQUAL(input_col, decoded_read->view()); | ||
| CUDF_TEST_EXPECT_COLUMNS_EQUAL(decoded_input->view(), decoded_read->view()); | ||
| } | ||
| #endif | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ignore this gem from clangd