-
Notifications
You must be signed in to change notification settings - Fork 1k
[VARIANT] Path-based Field Extraction for VariantArray #7946
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
base: main
Are you sure you want to change the base?
Conversation
18d88b0
to
b1afed1
Compare
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.
Thank you for this PR @carpecodeum
This is very cool
I think there is already a variant_get
implementation in https://github.com/apache/arrow-rs/blob/d809f19bc0fe2c3c1968f5111b6afa785d2e8bcd/parquet-variant-compute/src/variant_get.rs#L35-L34 contributed by @Samyak2
To take the next steps and implement shredding I think we will need two things:
- A way to create shredded variants
- A way to represent shredded variants
The idea of removing fields from Variant
s is interesting, though I wonder if that is an operation we would ever want to do on single Variant
instance -- it seems like removing fields for shredding will require copying the underlying bytes anyways, so I was thinking we might just want to create an output variant array entirely
Something like
fn variant_shred(input: VariantArray, output: VariantArray, schema: SchemaRef)
Maybe it is worth looking at how the java or go implementations work
use parquet_variant::VariantMetadata; | ||
use std::collections::HashSet; | ||
|
||
/// Represents a path element in a variant path |
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.
i think if you merge up from main this code will no longer be required
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.
i agree, a lot of this becomes redundant but get_field_bytes
is able to get field bytes from an object at the byte level, will this wont be required too?
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.
I am not quite sure what you are asking.
I think it might help to move shredded variant forward by writing the tests / examples of how variant_get should work with shredded arrays
I tried to work up a simple example here:
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.
I saw your PR it looks great, im myself trying to work up a few examples
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.
One idea would to be to try and create the other examples from https://docs.google.com/document/d/1pw0AWoMQY3SjD7R4LgbPvMjG_xSCtXp3rZHkVp9jpZ4/ in code
9a616b5
to
c712747
Compare
Is there any issue for implementing this? I would love to work on it |
I think we are discussing reading shredded variants on We are discussing creating shredded variants on I don't think we have enough of an idea of how this will work to break them down into finer grained tasks yet. |
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.
Partial review.
The overriding takeaway for me (which got in the way of reviewing the actual PR functionality) is that this PR has a dangerously high level of code duplication vs. existing code in the parquet-variant crate. Dangerous because it includes many bugs and inefficiencies that the other code already solved (which is ~inevitable with such a high amount of redundancy).
Can we please take the time to harmonize with existing code so reviewers can focus on the really important and exciting net new functionality instead of debugging a reinvented wheel?
if let Some(obj) = variant.as_object() { | ||
let mut field_names = Vec::new(); | ||
for i in 0..obj.len() { | ||
if let Some(field_name) = obj.field_name(i) { |
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.
Seems like this should be an unwrap
, since the only way to get None here is by an out of bounds index?
Hi @scovich yes, currently this is still in progress, which essentially means that I am still working on removing the redundancy, its just taking a bit more time than I thought for me because I had to focus on some other stuff the past few days, I still have it in draft as to just make sure people dont confuse it as a ready-to-go PR, but thanks for this review its very helpful. |
Ah, sorry if I was over-eager to review this PR. LMK if there are specific things that would be helpful to review, or if it's better to just wait for it to finish baking? |
…r functionalities
572af94
to
7dd6c23
Compare
After taking another look at both this PR and other PRs that have been opened or merged over the week, it seems like the only non-duplicate portions of this PR are the "get_field_names" and the "remove_field(s)" functionality. I've deduplicated this PR and cleaned things up to reflect this current status. Thanks @scovitch and @alamb for reviewing. Do we think this PR is both substantial and useful enough on its own? Or, do we want to close this PR and open one that's more targeted? I'm happy to follow through with either, favoring whatever the reviewers think would keep things clean. |
Problem is, those traits return references (which the compiler then transparently dereferences). AFAIK, it's impossible to implement those traits if the return value is "manufactured" by the function call itself, because that would require returning a reference to a temporary object that goes out of scope as soon as the function returns. ... which is why we have |
👋 Hi @carpecodeum -- I was checking in on this PR and seeing if it is ready for another round of review I am not sure if you have seen, but @rdblue gave us an early holiday 🎁 in the form of example shredded parquet variant files in parquet-testing: apache/parquet-testing#90 |
I don't really understand why in-place mutations are needed to implement It seems to me that we already have
What we are missing from the read side from what I can tell is the ability to read shredded variants (aka VariantArrays where the underlying array has a What would you think about trying to implement the code to make the tests in #7965 work? |
# Which issue does this PR close? - Part of #6736 - Closes #7941 - Closes #7965 # Rationale for this change This is has a proposal for how to structure shredded `VariantArray`s and the `variant_get` kernel If people like the basic idea I will file some more tickets to track additional follow on work It is based on ideas ideas from @carpecodeum in #7946 and @scovich in #7915 I basically took the tests from #7965 and the conversation with @scovich recorded from #7941 (comment) and I bashed out how this might look # What changes are included in this PR? 1. Update `VariantArray` to represent shredding 2. Add code to `variant_get` to support extracting paths as both variants and typed fields 3. A pattern that I think can represent shredding and extraction 4. Tests for same Note there are many things that are NOT in this PR that I envision doing as follow on PRs: 1. Support and implementing `Path`s 2. Support for shredded objects 3. Support shredded lists 4. Support nested objects / lists 5. Full casting support 6. Support for other output types: `StringArray`, `StringViewArray`, etc 8. Many performance improvements # Are these changes tested? Yes # Are there any user-facing changes? New feature --------- Co-authored-by: Samyak Sarnayak <[email protected]> Co-authored-by: Ryan Johnson <[email protected]>
Which issue does this PR close?
This PR implements efficient path-based field extraction and manipulation capabilities for
VariantArray
, enabling direct access to nested fields without expensive unshredding operations.Follow-up on #7919
variant_get
kernel for shredded variants #7941Rationale for this change
This work builds directly on the path navigation concepts introduced in #7919, sharing the fundamental VariantPathElement design with Field and Index variants. While PR #7919 provided a compute kernel approach with a variant_get function, this PR provides instance-based methods directly on VariantArray with a builder API using owned strings rather than PR #7919 vector-based approach.
This is a draft still, as the changes for #7919 got merged today, I still have to incorporate those changes, and looking forward to reviews and suggestions.
This PR is complementary to #7921, which implements schema-driven shredding during array construction. This PR provides runtime path-based access to both shredded and unshredded data, creating a complete solution for both efficient construction and efficient access of variant data.
Big Thanks to @mprammer @PinkCrow007 for their continued support throughout my
Variant
explorationWhat changes are included in this PR?
Field removal operations through methods like
remove_field
andremove_fields
enable removal of specific fields from variant data, crucial for shredding operations where temporary or debug fields need to be stripped.field_operations.rs
provides direct binary manipulation through functions likeget_path_bytes
,extract_field_bytes
, andremove_field_bytes
that operate on raw binary format without constructing intermediate objects.variant_parser.rs
supports all variant types with parsers for 17 different primitive types, providing the foundation for efficient binary navigation.The performance-critical byte operations could serve as the underlying implementation for PR #7919's compute kernel, potentially providing better performance for batch operations by avoiding object construction overhead. The field removal capabilities could extend PR #7919's functionality beyond extraction to comprehensive field manipulation. The instance-based approach provides different ergonomics that complement PR #7919's compute kernel approach.
This PR focuses on runtime access and manipulation rather than construction-time optimization, leaving build-time schema-driven shredding to PR #7921. Future work is integration with PR #7919's compute kernel approach, potentially using this PR's byte-level operations as the underlying implementation.
Are these changes tested?
Yes, tests are added
Are there any user-facing changes?
Not yet