github-actions[bot] commented on code in PR #66575:
URL: https://github.com/apache/doris/pull/66575#discussion_r3746370021


##########
be/src/format_v2/parquet/parquet_reader.cpp:
##########
@@ -72,104 +72,143 @@ const ParquetColumnSchema* schema_child_by_name(const 
ParquetColumnSchema& schem
     return child_it == schema.children.end() ? nullptr : child_it->get();
 }
 
-bool collect_variant_residual_leaf_ids(const ParquetColumnSchema& schema,
-                                       const format::LocalColumnIndex& 
projection,
-                                       std::vector<int>* residual_leaf_ids) {
+bool collect_variant_terminal_fallback_leaf_ids(const ParquetColumnSchema& 
schema,
+                                                const 
format::LocalColumnIndex& projection,
+                                                std::vector<int>* 
residual_leaf_ids) {
     DORIS_CHECK(residual_leaf_ids != nullptr);
     const auto* value = schema_child_by_name(schema, "value");
     const auto* typed_value = schema_child_by_name(schema, "typed_value");
-    if (value != nullptr && typed_value != nullptr) {
-        if (value->kind != ParquetColumnSchemaKind::PRIMITIVE || 
value->leaf_column_id < 0) {
+    if (value != nullptr && value->kind == ParquetColumnSchemaKind::PRIMITIVE 
&&
+        typed_value != nullptr) {
+        if (value->leaf_column_id < 0) {
             return false;
         }
+        const auto typed_projection_it =
+                std::ranges::find_if(projection.children, [&](const auto& 
child_projection) {
+                    return child_projection.local_id() == 
typed_value->local_id;
+                });
+        if (typed_projection_it == projection.children.end()) {
+            return false;
+        }
+        if (typed_value->kind != ParquetColumnSchemaKind::PRIMITIVE) {
+            return collect_variant_terminal_fallback_leaf_ids(*typed_value, 
*typed_projection_it,
+                                                              
residual_leaf_ids);
+        }
+        // Object residual keys are disjoint from shredded keys. Only the 
fallback paired with the

Review Comment:
   [P1] Preserve the root fallback for paths propagated through explode
   
   `AccessPathPlanCollector` encodes `select x['k'] ... explode(v)` as the 
legacy path `v/k`, so the scan no longer knows that the generator must consume 
`v` itself as an array. A valid heterogeneous Variant row group can have object 
`typed_value.k` in its shared schema while array-valued rows live in the root 
residual `value`; `k.value` is all NULL for those rows, so this terminal-only 
check accepts the partial leaf and drops the arrays. `explode` then 
casts/materializes the whole input Variant as ARRAY, but a partial Parquet 
Variant cannot materialize its root. Please preserve container provenance (or 
force full projection for generator-derived paths) and cover a mixed row group 
with root residual arrays plus shredded object `k`.



##########
be/src/format_v2/parquet/parquet_scan.cpp:
##########
@@ -252,6 +252,75 @@ std::vector<format::LocalColumnIndex> 
physical_non_predicate_columns(
     return columns;
 }
 
+struct VariantRowGroupProjectionCounts {
+    size_t leaf = 0;
+    size_t full = 0;
+};
+
+VariantRowGroupProjectionCounts finalize_variant_projections_for_row_group(
+        const tparquet::RowGroup& row_group,
+        const std::vector<std::unique_ptr<ParquetColumnSchema>>& file_schema,
+        std::vector<format::LocalColumnIndex>* projections) {
+    DORIS_CHECK(projections != nullptr);
+    VariantRowGroupProjectionCounts counts;
+    for (auto& projection : *projections) {
+        const int32_t local_id = projection.local_id();
+        if (local_id < 0 || local_id >= 
static_cast<int32_t>(file_schema.size()) ||
+            !file_schema[local_id]->contains_variant) {
+            continue;
+        }
+        counts.leaf += detail::finalize_variant_leaf_projection_for_row_group(
+                row_group, *file_schema[local_id], &projection, &counts.full);
+    }
+    return counts;
+}
+
+void prepare_row_group_physical_projection(
+        const tparquet::RowGroup& row_group,
+        const std::vector<std::unique_ptr<ParquetColumnSchema>>& file_schema,
+        const format::FileScanRequest& request, RowGroupReadPlan* 
row_group_plan) {
+    DORIS_CHECK(row_group_plan != nullptr);
+    const auto may_project_variant_leaf = [&](const auto& projections) {
+        return std::ranges::any_of(projections, [&](const auto& projection) {
+            const int32_t local_id = projection.local_id();
+            return local_id >= 0 && local_id < 
static_cast<int32_t>(file_schema.size()) &&
+                   file_schema[local_id] != nullptr && 
file_schema[local_id]->contains_variant &&
+                   format::is_partial_projection(&projection);
+        });
+    };
+    if (!may_project_variant_leaf(request.predicate_columns) &&
+        !may_project_variant_leaf(request.non_predicate_columns)) {
+        row_group_plan->physical_predicate_columns = {};
+        row_group_plan->physical_non_predicate_columns = {};
+        row_group_plan->has_row_group_physical_projection = false;
+        row_group_plan->variant_leaf_projection_columns = 0;
+        row_group_plan->variant_full_projection_columns = 0;
+        return;
+    }
+    row_group_plan->physical_predicate_columns = request.predicate_columns;

Review Comment:
   [P2] Avoid copying the complete projection into every row-group plan
   
   As soon as any partial top-level projection belongs to a schema containing 
Variant, this copies every predicate and output `LocalColumnIndex` tree into 
every candidate row group. `physical_request_for_row_group()` then clones the 
full `FileScanRequest` again for footer/deferred probes, and 
`ParquetReader::open()` retains each surviving projection-bearing plan both in 
`_state->scan_plan` and in the scheduler. For S surviving groups and P 
wide/deep projection nodes, that adds O(S x P) persistent planning state 
(roughly twice), plus repeated request-copy CPU before any batch is read. 
Please represent the row-group leaf/full decision as a compact delta or shared 
immutable projection shape, pass request views to metadata helpers, and avoid 
retaining two deep plan copies.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to