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


##########
be/benchmark/parquet/benchmark_parquet_reader.hpp:
##########
@@ -275,6 +322,22 @@ inline VExprContextSPtr make_predicate(int 
column_position, int selectivity_perc
     return context;
 }
 
+inline VExprContextSPtr make_complex_residual_predicate(int 
selectivity_percent) {
+    TExprNode node;
+    node.__set_node_type(TExprNodeType::COMPOUND_PRED);
+    node.__set_opcode(TExprOpcode::COMPOUND_AND);
+    node.__set_type(std::make_shared<DataTypeUInt8>()->to_thrift());
+    node.__set_num_children(2);
+    node.__set_is_nullable(false);
+    auto compound = VCompoundPred::create_shared(node);
+    compound->add_child(std::make_shared<Int32PairSumLessThanExpr>(0, 1, 2 * 
selectivity_percent));

Review Comment:
   [P2] Exercise a production-eligible expression
   
   This custom leaf inherits `VExpr`'s safe result because it has no children, 
but a real planned `(c0 + c1) < bound` tree contains a 
`VectorizedFnCall("add")`, which is absent from the recursive selected-row 
allowlist. Production therefore takes the eager fallback and reads all 
predicate columns, so this benchmark and the matching tests do not exercise the 
advertised workload. Please construct the production expression tree and assert 
its counters; if arithmetic is intentionally unsafe, use and document a 
genuinely reachable multi-column predicate instead.



##########
be/benchmark/parquet/AGENTS.md:
##########
@@ -42,7 +42,7 @@ be/output/lib/benchmark_test --benchmark_list_tests \
   | grep -c '^ParquetDecoder/'  # currently 152
 
 be/output/lib/benchmark_test --benchmark_list_tests \
-  | grep -c '^ParquetReader/'   # currently 137
+  | grep -c '^ParquetReader/'   # currently 138

Review Comment:
   [P2] Correct the reader registration count
   
   This smoke-check total is still stale. Deduplicating the exact generator 
tuples produces 152 registrations (6 operation baselines + 6 encoding + 14 
fixed-width-axis + 7 width/position + 119 
nullable/pattern/selectivity/projection), not 138. A healthy full reader run 
would therefore disagree with the documented check. Please update both count 
references and add an exact scenario-count/unique-name assertion so this gate 
cannot drift again.



##########
be/src/format_v2/parquet/parquet_scan.cpp:
##########
@@ -1875,15 +1986,45 @@ Status 
ParquetScanScheduler::read_filter_columns(int64_t batch_rows,
     };
 
     RETURN_IF_ERROR(read_round_by_round());
-    // Single-column expressions only touch the just-read column, so earlier 
columns can retain
-    // their own row mappings. Compact only when a later expression needs a 
shared coordinate
-    // space; otherwise the final boundary can discard hidden predicate 
payloads without scanning
-    // them again.
-    if (!schedule.remaining_conjuncts.empty()) {
+    if (*selected_rows == 0) {
+        RETURN_IF_ERROR(skip_unmaterialized_predicate_columns());
+        return compact_predicate_columns_with_profile(true);
+    }
+
+    // Complex residuals keep their original conjunct order. Materialize only 
the columns needed
+    // by the next reachable expression, then compact previously read columns 
into the same row
+    // space before evaluating it. This is the scanner-side equivalent of 
expression-triggered
+    // lazy columns: a conjunct that rejects the batch prevents later-only 
columns from decoding.
+    for (const auto& stage : schedule.remaining_stages) {

Review Comment:
   [P1] Avoid quadratic stage-alignment work
   
   This loop revalidates every previously materialized predicate column before 
every stage, even when the preceding stage left `SelectionVector` unchanged. 
For N all-pass safe pair predicates (`c0 < c1`, `c2 < c3`, ...), stage i scans 
2i full row mappings, so the added alignment overhead is O(N^2 * batch_rows): 
661,903,500 comparisons for 100 pairs at a 65,535-row batch, before expression 
work. Please track the selection generation or dirty state and skip alignment 
when it has not changed, with an all-pass chain test or benchmark that protects 
linear scaling.



##########
be/src/format_v2/parquet/parquet_scan.cpp:
##########
@@ -1220,18 +1278,31 @@ detail::PredicateConjunctSchedule 
build_predicate_conjunct_schedule(
             // optimization, so any unsafe conjunct disables the per-column 
schedule for the batch.
             schedule.remaining_conjuncts = request.conjuncts;
             schedule.single_column_conjuncts.clear();
+            schedule.remaining_stages.clear();
+            schedule.supports_lazy_materialization = false;
             return schedule;
         }
         std::set<int> referenced_positions;
         conjunct->root()->collect_slot_column_ids(referenced_positions);
         if (referenced_positions.size() != 1) {
             schedule.remaining_conjuncts.push_back(conjunct);
+            if (!append_residual_stages(conjunct, conjunct->root(), 
predicate_block_positions,

Review Comment:
   [P1] Preserve localized CAST error behavior
   
   The safety check here runs after ColumnMapper has cloned an ordinary 
`VCastExpr` into `format::Cast`. Unlike `VCastExpr` (explicitly unsafe; only 
`TryCastExpr` opts back in), `format::Cast` has no safety override and inherits 
a true result for a deterministic slot child. A localized compound such as `(c0 
< c1) AND (CAST(c2 AS table_type) = literal)` now filters on the first child 
and runs the potentially failing cast only on survivors, hiding an error in a 
rejected row that the former whole-root execution evaluated. Please preserve or 
recheck ordinary-cast safety after localization (for example, make 
`format::Cast` unsafe) and add a partial-survival failing-cast test.



-- 
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