Add logical type inspection for raw Parquet VARIANT values - #23491
Add logical type inspection for raw Parquet VARIANT values#23491abigalekim wants to merge 2 commits into
Conversation
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds the public ChangesVARIANT type-ID extraction
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related issues
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
cpp/include/cudf/io/experimental/variant_spec.hpp (1)
56-71: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssign explicit values to
variant_logical_type.The enumerators of
variant_logical_typerely on implicit sequential values.get_variant_type_idcasts these values toint32_tand returns them as output data. If a new logical type is inserted in the middle of this list later, every subsequent numeric ID shifts silently. This can break downstream consumers that persist or compare these IDs.Assign each enumerator an explicit value now, while the API is new, to fix the wire contract.
♻️ Proposed fix to pin enumerator values
enum class variant_logical_type : uint8_t { - object, - array, - null_value, - boolean, - long_value, - string, - double_value, - decimal, - date, - timestamp, - timestamp_ntz, - float_value, - binary, - uuid + object = 0, + array = 1, + null_value = 2, + boolean = 3, + long_value = 4, + string = 5, + double_value = 6, + decimal = 7, + date = 8, + timestamp = 9, + timestamp_ntz = 10, + float_value = 11, + binary = 12, + uuid = 13 };🤖 Prompt for 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. In `@cpp/include/cudf/io/experimental/variant_spec.hpp` around lines 56 - 71, Update the variant_logical_type enum so every enumerator has an explicit numeric value, preserving its current sequential IDs and establishing a stable wire contract for get_variant_type_id. Use the existing declaration order and assign values starting at zero through uuid; do not change the enum members or their ordering.cpp/src/io/parquet/experimental/variant_extract.cu (1)
790-817: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract the repeated value-span construction into a helper.
Lines 803-806 repeat the same offset/span construction already used in
cast_variant_primitive_kernel(lines 632-636) andcast_variant_string_fn::operator()(lines 670-674). This is now the third copy of the same three-line idiom.Extract a small
__device__helper that returns the valuedevice_span<uint8_t const>for a row, and call it from all three sites. This reduces duplication and keeps future changes to the span-lookup logic in one place.♻️ Proposed helper extraction
__device__ inline device_span<uint8_t const> value_span_at( cudf::lists_column_device_view const& values, size_type row) { auto const val_begin = values.offset_at(row); auto const val_end = values.offset_at(row + 1); return {values.child().data<uint8_t>() + val_begin, static_cast<std::size_t>(val_end - val_begin)}; }auto const val_begin = values.offset_at(row); auto const val_end = values.offset_at(row + 1); - device_span<uint8_t const> const val{values.child().data<uint8_t>() + val_begin, - static_cast<std::size_t>(val_end - val_begin)}; + auto const val = value_span_at(values, row);🤖 Prompt for 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. In `@cpp/src/io/parquet/experimental/variant_extract.cu` around lines 790 - 817, Extract the repeated value offset/span construction into a shared __device__ helper, such as value_span_at, accepting the lists_column_device_view and row and returning device_span<uint8_t const>. Replace the duplicated three-line logic in get_variant_type_id_kernel, cast_variant_primitive_kernel, and cast_variant_string_fn::operator() with calls to this helper, preserving the existing span contents and behavior.
🤖 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/experimental/variant_extract_test.cpp`:
- Around line 1621-1657: Increase num_rows in
GetVariantTypeIdTest.LargeMultiRowColumn from 128 to a value above the kernel
block size, such as 600, so get_variant_type_id exercises the multi-block
grid-stride path while preserving the existing cycling type coverage and
expected_ids generation.
---
Nitpick comments:
In `@cpp/include/cudf/io/experimental/variant_spec.hpp`:
- Around line 56-71: Update the variant_logical_type enum so every enumerator
has an explicit numeric value, preserving its current sequential IDs and
establishing a stable wire contract for get_variant_type_id. Use the existing
declaration order and assign values starting at zero through uuid; do not change
the enum members or their ordering.
In `@cpp/src/io/parquet/experimental/variant_extract.cu`:
- Around line 790-817: Extract the repeated value offset/span construction into
a shared __device__ helper, such as value_span_at, accepting the
lists_column_device_view and row and returning device_span<uint8_t const>.
Replace the duplicated three-line logic in get_variant_type_id_kernel,
cast_variant_primitive_kernel, and cast_variant_string_fn::operator() with calls
to this helper, preserving the existing span contents and behavior.
🪄 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: f1423210-95f8-4ad2-ab54-2d2cafd21e53
📒 Files selected for processing (4)
cpp/include/cudf/io/experimental/variant.hppcpp/include/cudf/io/experimental/variant_spec.hppcpp/src/io/parquet/experimental/variant_extract.cucpp/tests/io/experimental/variant_extract_test.cpp
| TEST_F(GetVariantTypeIdTest, LargeMultiRowColumn) | ||
| { | ||
| // 128 rows cycling through all types that get_variant_type_id can classify. | ||
| auto const stream = cudf::test::get_default_stream(); | ||
|
|
||
| struct row_spec { | ||
| std::vector<uint8_t> blob; | ||
| int32_t expected_id; | ||
| }; | ||
|
|
||
| std::vector<row_spec> const types{ | ||
| {enc_null(), static_cast<int32_t>(LT::null_value)}, | ||
| {enc_bool(false), static_cast<int32_t>(LT::boolean)}, | ||
| {enc_int8(1), static_cast<int32_t>(LT::long_value)}, | ||
| {enc_int16(2), static_cast<int32_t>(LT::long_value)}, | ||
| {enc_int32(3), static_cast<int32_t>(LT::long_value)}, | ||
| {enc_int64(4), static_cast<int32_t>(LT::long_value)}, | ||
| {enc_float64(5.0), static_cast<int32_t>(LT::double_value)}, | ||
| {enc_short_string("x"), static_cast<int32_t>(LT::string)}, | ||
| {enc_long_string(std::string(70, 'z')), static_cast<int32_t>(LT::string)}, | ||
| }; | ||
| constexpr int num_rows = 128; | ||
| std::vector<std::vector<uint8_t>> blobs(num_rows); | ||
| std::vector<int32_t> expected_ids(num_rows); | ||
| for (int i = 0; i < num_rows; ++i) { | ||
| auto const& spec = types[i % types.size()]; | ||
| blobs[i] = spec.blob; | ||
| expected_ids[i] = spec.expected_id; | ||
| } | ||
|
|
||
| auto values = make_list_u8_nullable(blobs, std::vector<bool>(num_rows, true)); | ||
| auto got = cudf::io::parquet::experimental::get_variant_type_id(*values, stream); | ||
|
|
||
| cudf::test::fixed_width_column_wrapper<int32_t> expected(expected_ids.begin(), | ||
| expected_ids.end()); | ||
| CUDF_TEST_EXPECT_COLUMNS_EQUAL(*got, expected); | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Increase LargeMultiRowColumn past the kernel's block size.
get_variant_type_id_kernel uses block_size = 256 (cpp/src/io/parquet/experimental/variant_extract.cu). This test uses num_rows = 128, so grid_1d{128, 256} launches a single block. The test does not exercise the kernel's grid-stride loop across multiple blocks.
Increase num_rows past 256 (for example 600) so the test covers the multi-block path.
As per path instructions: "Tests must cover empty inputs, nulls, sliced columns, boundary and multi-block sizes, and non-ASCII UTF-8 for string tests."
🤖 Prompt for 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.
In `@cpp/tests/io/experimental/variant_extract_test.cpp` around lines 1621 - 1657,
Increase num_rows in GetVariantTypeIdTest.LargeMultiRowColumn from 128 to a
value above the kernel block size, such as 600, so get_variant_type_id exercises
the multi-block grid-stride path while preserving the existing cycling type
coverage and expected_ids generation.
Source: Path instructions
Description
Implements feature mentioned in #23183.
Checklist