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


##########
fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateGroupByKeyTest.java:
##########
@@ -181,6 +183,25 @@ void testEliminateByEqual() {
                                 && 
agg.getGroupByExpressions().get(0).toSql().equals("name")));
     }
 
+    @Test
+    void testEliminateByPkWithOutputNeeded() throws Exception {
+        // Regression: when a group-by key (name) is FD-redundant (id -> name)
+        // but still appears in SELECT, it should be removed from group-by
+        // and wrapped with ANY_VALUE in the output.
+        addConstraint("alter table t1 add constraint pk2 primary key (id)");
+        PlanChecker.from(connectContext)
+                .analyze("select id, name, count(*) from t1 group by id, name")
+                .customRewrite(new EliminateGroupByKey())

Review Comment:
   This regression only runs `EliminateGroupByKey` through 
`PlanChecker.customRewrite()`, which wraps it as `RuleType.TEST_REWRITE`. That 
proves the visitor logic, but not the production 
`custom(RuleType.ELIMINATE_GROUP_BY_KEY, ...)` registration/disable bit, nor 
the MV pre-rewrite mask added for `ELIMINATE_GROUP_BY_KEY`. Please add a 
production-path check, for example a 
`.rewrite()`/`disable_nereids_rules=ELIMINATE_GROUP_BY_KEY` case for this query 
and a `PreMaterializedViewRewriterTest` assertion that 
`ruleSetApplied(RuleType.ELIMINATE_GROUP_BY_KEY)` triggers `needPreRewrite`.



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateGroupByKey.java:
##########
@@ -38,69 +42,156 @@
 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 List<Rule> buildRules() {
-        return ImmutableList.of(
-                RuleType.ELIMINATE_GROUP_BY_KEY.build(
-                        logicalProject(logicalAggregate().when(agg -> 
!agg.getSourceRepeat().isPresent()))
-                                .then(proj -> {
-                                    LogicalAggregate<? extends Plan> agg = 
proj.child();
-                                    LogicalAggregate<Plan> newAgg = 
eliminateGroupByKey(agg, proj.getInputSlots());
-                                    if (newAgg == null) {
-                                        return null;
-                                    }
-                                    return proj.withChildren(newAgg);
-                                })),
-                RuleType.ELIMINATE_FILTER_GROUP_BY_KEY.build(
-                        logicalProject(logicalFilter(logicalAggregate()
-                                .when(agg -> 
!agg.getSourceRepeat().isPresent())))
-                                .then(proj -> {
-                                    LogicalAggregate<? extends Plan> agg = 
proj.child().child();
-                                    Set<Slot> requireSlots = new 
HashSet<>(proj.getInputSlots());
-                                    
requireSlots.addAll(proj.child(0).getInputSlots());
-                                    LogicalAggregate<Plan> newAgg = 
eliminateGroupByKey(agg, requireSlots);
-                                    if (newAgg == null) {
-                                        return null;
-                                    }
-                                    return 
proj.withChildren(proj.child().withChildren(newAgg));
-                                })
-                )
-        );
+    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);
     }
 
-    LogicalAggregate<Plan> eliminateGroupByKey(LogicalAggregate<? extends 
Plan> agg, Set<Slot> requireOutput) {
-        Set<Expression> removeExpression = findCanBeRemovedExpressions(agg, 
requireOutput,
+    @Override
+    public Plan visit(Plan plan, Map<ExprId, ExprId> replaceMap) {
+        plan = visitChildren(this, plan, replaceMap);
+        plan = exprIdReplacer.rewriteExpr(plan, replaceMap);

Review Comment:
   This upward rewrite misses aggregates whose only changed reference is in 
`GROUP BY`. A reduced shape is:
   
   ```text
   Aggregate(groupBy=[name#old], output=[count(*)])
     Project(name#old)
       Aggregate(groupBy=[id#i, name#old], output=[id#i, name#old])
   ```
   
   After the inner `Project(Aggregate)` rewrites `name#old` to 
`any_value(name#old) AS name#new`, the outer aggregate needs its group key 
rewritten to `name#new`. But `ExprIdRewriter` delegates to 
`ExpressionRewrite.AggExpressionRewrite`, which computes `newGroupByExprs` and 
then returns the old aggregate whenever the output list is unchanged, so this 
group-by-only change is discarded. The resulting plan keeps grouping by 
`name#old` while its child now outputs `name#new`, which `CheckAfterRewrite` 
reports as an input slot missing from the child output. Please make the 
aggregate expression rewrite rebuild when either group-by expressions or 
outputs change, or handle aggregate ancestors directly in this rule before 
propagating the replacement map.



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