-
Notifications
You must be signed in to change notification settings - Fork 569
Revise Lenses API and definitions to include scatter columns #11871
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
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.
Pull Request Overview
This PR refactors the Lenses API to support three distinct lens types based on row transformation patterns: OneToOne (1:1 mapping), Static (timeless data), and ToMany (1:N scatter). The new builder-based API uses output_columns, output_static_columns, and output_scatter_columns methods to create scoped column groups, replacing the previous single-method approach.
Key Changes:
- Introduced
LensKindenum to distinguish between lens transformation types - Added builder pattern with scoped output methods for different lens modes
- Implemented
Explodetransformation for flattening nested lists in scatter operations
Reviewed Changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| examples/rust/lenses/src/main.rs | Updated lens construction to use new builder API with scoped column methods |
| crates/utils/re_arrow_combinators/tests/util.rs | Added helper utility for displaying arrays as record batches in tests |
| crates/utils/re_arrow_combinators/tests/transform.rs | Refactored to use shared utility module |
| crates/utils/re_arrow_combinators/tests/snapshots/*.snap | Added snapshot test files for explode functionality |
| crates/utils/re_arrow_combinators/tests/explode.rs | New test file for explode transformation |
| crates/utils/re_arrow_combinators/src/reshape.rs | Implemented Explode transformation for scattering list elements |
| crates/top/re_sdk/src/lenses/snapshots/*.snap | Added snapshots for scatter column tests |
| crates/top/re_sdk/src/lenses/op.rs | Minor import restructuring |
| crates/top/re_sdk/src/lenses/mod.rs | Updated exports to include new builder types |
| crates/top/re_sdk/src/lenses/builder.rs | New builder API with ColumnsBuilder, StaticColumnsBuilder, and ScatterColumnsBuilder |
| crates/top/re_sdk/src/lenses/ast.rs | Major refactoring to support new lens types and transformation logic |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
23173e5 to
4abf140
Compare
Rethink target entity paths Clean up terminology: `Timeline` vs `Time`
4abf140 to
01ad210
Compare
|
Web viewer built successfully.
View image diff on kitdiff. Note: This comment is updated whenever you push a commit. |
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 only have a superficial understanding of lenses, so I mostly reviewed the code.
It mostly looks good except the pervasive logging of errors instead of returning them, which is very unidiomatic. If we're going that route I want a good motivation for it, and tests that include checking the log output for any errors!
crates/top/re_sdk/src/lenses/ast.rs
Outdated
| ToMany { | ||
| target_entity: TargetEntity, | ||
| components: Vec<ComponentOutput>, | ||
| timelines: Vec<TimeOutput>, |
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.
Does this mean timelines is never empty? Should we maybe use vec1 for it?
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.
Sorry the doc comment was confusing here. Time columns defined via Lenses are optional.
Regarding vec1: Might make sense for component columns, but these structs would be backing a potential future config language so that would make them weird to use? A just saw that vec1 has a serde feature.
| re_log::error!( | ||
| "Lens operations failed for component columns '{}': {err}", | ||
| output.component_descr | ||
| ); |
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.
Are we sure we should not abort the operation if this happens?
| } else { | ||
| re_log::error_once!( | ||
| "Output for timeline '{timeline_name}' must produce data type {}", | ||
| DataType::List(Arc::new(Field::new_list_field(DataType::Int64, false))), |
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.
yeeshus arrow-rs can be verbose sometimes…
| let inner_offsets = inner_list.value_offsets(); | ||
|
|
||
| for j in start..end { | ||
| new_validity.push(!inner_list.is_null(j)); |
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.
| new_validity.push(!inner_list.is_null(j)); | |
| new_validity.push(inner_list.is_valid(j)); |
| type Source = ListArray; | ||
| type Target = ListArray; | ||
|
|
||
| fn transform(&self, source: &Self::Source) -> Result<Self::Target, Error> { |
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.
| fn transform(&self, source: &Self::Source) -> Result<Self::Target, Error> { | |
| fn transform(&self, source: &Self::Source) -> Result<Self::Target, Error> { | |
| re_tracing::profile_function!(); |
| @@ -0,0 +1,21 @@ | |||
| --- | |||
| source: crates/utils/re_arrow_combinators/tests/explode.rs | |||
| expression: "format!(\"{}\", DisplayRB(result))" | |||
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.
It would be a lot easier to check these tests if these snapshot tests included the input.
Alternatively, put the snapshot output into the test files with inline snapshots
| let explode = Explode; | ||
| let result = explode.transform(&input).unwrap(); | ||
|
|
||
| insta::assert_snapshot!("primitives", format!("{}", DisplayRB(result))); |
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.
Consider using https://docs.rs/insta/latest/insta/#inline-snapshots
crates/top/re_sdk/src/lenses/ast.rs
Outdated
| Err(err) => { | ||
| re_log::error_once!( | ||
| "Failed to replicate timeline '{}' for entity '{entity_path}': {err}", | ||
| timeline_name | ||
| ); | ||
| return None; |
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.
In some places you log errors and continue, but here you log an error and abort. Why not just return an Err instead?
What
This PR revises the Lenses API and specification by introducing different types of lenses that are centered around the time columns:
OneToOnelenses have the same amount of output rows as their input column.Staticlenses don't have any time columns attached to them.OneToManylenses produce multiple rows for any given row in their input column.These kind of lenses are accessed in the
LensBuilderviacolumns,static_columns, andscatter_columnsmethods, which create scopes that can be used to bundle columns together.Although the concept of chunks is not exposed in the Lenses API, under the hood all columns (time or component) specified in a scope (
LensKind) will end up in the same chunk.Context
The new scatter columns operating mode is required for "plural" MCAP messages that have multiple timestamps defined in a single message. An example for this is
foxglove.FrameTransforms.