From 0b29aeec05b926c6ea9300ef69a83f0f5855f1ed Mon Sep 17 00:00:00 2001 From: gitRasheed <99349713+gitRasheed@users.noreply.github.com> Date: Mon, 26 Oct 2026 21:52:38 +0000 Subject: [PATCH] perf(layout): read a path below a nullable struct's field without the rest of the field A nullable struct expands a field access `$.x` to `mask($.x, is_not_null($))`. For a path below the field, such as `$.x.q`, the mask then sits between the path and the field, so the partitioner hands the field's reader a bare `$` and the whole of `x` is read. Mask the whole path instead. On a file with `t: {x: {p, q}, r}`, both nullable, reading `$.t.x.q` or filtering on `$.t.x.q > n` read 6.0 MB before and 160 KB after. Signed-off-by: gitRasheed <99349713+gitRasheed@users.noreply.github.com> --- vortex-layout/src/layouts/struct_/reader.rs | 136 ++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/vortex-layout/src/layouts/struct_/reader.rs b/vortex-layout/src/layouts/struct_/reader.rs index 30547d298eb..e0d2594ec41 100644 --- a/vortex-layout/src/layouts/struct_/reader.rs +++ b/vortex-layout/src/layouts/struct_/reader.rs @@ -320,6 +320,17 @@ fn expand_struct_root( .first() .is_some_and(BoundExpression::is_root) { + // Masking `$.x` inside `$.x.q` would hide the path from the partitioner, which + // would then read all of `x`. Mask the whole path instead. + if validity.is_some() + && let Some(path) = field_path(&node, packed, fields)? + { + return Ok(Transformed { + value: with_validity(path), + changed: true, + order: TraversalOrder::Skip, + }); + } return Ok(Transformed::no(node)); } @@ -380,6 +391,35 @@ fn expand_struct_root( .into_inner()) } +/// Rebuilds a chain of `get_item` and `select` that starts at `$.field` on the field's expression +/// in `packed`, or returns `None` if `node` is not such a chain. +fn field_path( + node: &BoundExpression, + packed: &BoundExpression, + fields: &StructFields, +) -> VortexResult> { + let Some(scalar_fn) = node.as_scalar() else { + return Ok(None); + }; + if !scalar_fn.is::() && !scalar_fn.is::