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


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateGroupByKey.java:
##########
@@ -110,17 +250,24 @@ public static Set<Expression> 
findCanBeRemovedExpressions(LogicalAggregate<? ext
 
         FuncDeps funcDeps = dataTrait.getAllValidFuncDeps(validSlots);
         if (funcDeps.isEmpty()) {
-            return new HashSet<>();
+            return new FindResult(new HashSet<>(), new HashSet<>());
         }
 
         Set<Set<Slot>> minGroupBySlots = funcDeps.eliminateDeps(new 
HashSet<>(groupBySlots.values()), requireOutput);
         Set<Expression> removeExpression = new HashSet<>();
+        Set<Expression> wrapWithAnyValue = new HashSet<>();
         for (Entry<Expression, Set<Slot>> entry : groupBySlots.entrySet()) {
-            if (!minGroupBySlots.contains(entry.getValue())
-                    && !requireOutput.containsAll(entry.getValue())) {
-                removeExpression.add(entry.getKey());
+            if (!minGroupBySlots.contains(entry.getValue())) {
+                // FD redundant: can remove from group-by
+                if (!requireOutput.containsAll(entry.getValue())) {
+                    // Not needed in output either: remove completely
+                    removeExpression.add(entry.getKey());
+                } else {
+                    // Still needed in output: remove from group-by, wrap with 
ANY_VALUE in output
+                    wrapWithAnyValue.add(entry.getKey());

Review Comment:
   **[P1] Suppress invalid scan constraints before this branch**
   
   This added `ANY_VALUE` path turns two existing 
`LogicalOlapScan.computeUnique()` ordering gaps into wrong results because 
`super.computeUnique()` imports table constraints before the scan-specific 
guards run:
   
   - A direct non-base index containing `a,c` for a table-level `UNIQUE(a,b)` 
resolves only `{a}` in `findSlotsByColumn()`. The selected-index return then 
leaves that singleton advertised as unique, so `GROUP BY a,c` becomes `GROUP BY 
a` plus `ANY_VALUE(c)` and merges distinct `(1,'x')`/`(1,'y')` groups.
   - A MOR unique-key table with an explicit constraint on `k` and 
`read_mor_as_dup_tables='*'` deliberately exposes versions `(1,10)`, `(1,20)`, 
and `(1,30)`, but the raw-read return also leaves the superclass `k -> v` trait 
intact. This branch collapses those three `(k,v)` groups to one.
   
   Please suppress superclass constraints for raw-version reads and require 
every constrained column to be present before registering a constraint on a 
selected index, then add executed result regressions for both modes.



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateGroupByKey.java:
##########
@@ -17,90 +17,230 @@
 
 package org.apache.doris.nereids.rules.rewrite;
 
-import org.apache.doris.nereids.annotation.DependsRules;
+import org.apache.doris.nereids.jobs.JobContext;
 import org.apache.doris.nereids.properties.DataTrait;
 import org.apache.doris.nereids.properties.FuncDeps;
-import org.apache.doris.nereids.rules.Rule;
-import org.apache.doris.nereids.rules.RuleType;
+import org.apache.doris.nereids.trees.expressions.Alias;
+import org.apache.doris.nereids.trees.expressions.ExprId;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.NamedExpression;
 import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.expressions.functions.agg.AnyValue;
 import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.algebra.Aggregate;
 import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
+import org.apache.doris.nereids.trees.plans.logical.LogicalCTEConsumer;
+import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
+import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
+import org.apache.doris.nereids.trees.plans.visitor.CustomRewriter;
+import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanRewriter;
 
-import com.google.common.collect.ImmutableList;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
-
 /**
  * Eliminate group by key based on fd item information.
  * such as:
  *  for a -> b, we can get:
  *          group by a, b, c  => group by a, c
+ *
+ * When a group-by key is FD-redundant but still needed in the output,
+ * it is wrapped with any_value() and assigned a fresh ExprId.
+ * Upper plan references are rewritten via ExprIdRewriter so that
+ * all ancestor nodes see the new ExprIds.
  */
-@DependsRules({EliminateGroupBy.class, ColumnPruning.class})
-public class EliminateGroupByKey implements RewriteRuleFactory {
+public class EliminateGroupByKey extends DefaultPlanRewriter<Map<ExprId, 
ExprId>> implements CustomRewriter {
+    private ExprIdRewriter exprIdReplacer;
+
+    @Override
+    public Plan rewriteRoot(Plan plan, JobContext jobContext) {
+        if (!plan.containsType(Aggregate.class)) {
+            return plan;
+        }
+        Map<ExprId, ExprId> replaceMap = new HashMap<>();
+        ExprIdRewriter.ReplaceRule replaceRule = new 
ExprIdRewriter.ReplaceRule(replaceMap, false);
+        exprIdReplacer = new ExprIdRewriter(replaceRule, jobContext);
+        return plan.accept(this, replaceMap);
+    }
+
+    @Override
+    public Plan visit(Plan plan, Map<ExprId, ExprId> replaceMap) {
+        plan = visitChildren(this, plan, replaceMap);
+        plan = exprIdReplacer.rewriteExpr(plan, replaceMap);

Review Comment:
   **[P1] Rewrite lateral `ON` conjuncts with generator arguments**
   
   This whole-tree replacement can leave `LogicalGenerate` internally 
inconsistent. A reduced reachable tree is:
   
   ```text
   Generate[UNNEST(tags#T2), ON tag#G = name#N]  // name#N is stale
     Project[keep#K, name#N2, tags#T2, cnt#C]
       Aggregate[group=k, output=k, ANY_VALUE(name)#N2, ANY_VALUE(tags)#T2, 
count(*)#C]
         Project[k, upper(k) AS name#N, split(k, ',') AS tags#T]
           Scan
   ```
   
   The lower deterministic expressions provide valid `k -> {name,tags}` FDs, 
and a computed `keep` output retains the upper Project. 
`LogicalGenerate.getExpressions()` includes both generators and lateral 
conjuncts, but `GenerateExpressionRewrite` rewrites only `getGenerators()`; 
`withGenerators()` preserves `ON tag#G = name#N` after the child has switched 
to `name#N2`. Final slot validation therefore rejects the query. Please 
rewrite/rebuild the conjuncts in the same operation and add a production 
rewrite test using a grouped derived table with `JOIN LATERAL UNNEST(...) ... 
ON ...`.



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