Copilot commented on code in PR #13328:
URL: https://github.com/apache/gluten/pull/13328#discussion_r4294737802


##########
gluten-substrait/src/main/scala/org/apache/gluten/extension/joinagg/ImplementJoinAggregate.scala:
##########
@@ -150,16 +179,74 @@ case class ImplementJoinAggregate(spark: SparkSession) 
extends SparkStrategy {
     } else {
       childPlan
     }
+    val stageChild = if (stage == AggregationStage.TWO_STAGE) {
+      buildMapperAggregate(grouping, preparedChild, rewrittenAggExprs)
+    } else {
+      preparedChild
+    }
+    val stageExpressions = if (stage == AggregationStage.TWO_STAGE) {
+      rewrittenAggExprs.map {
+        ae =>
+          val mode = ae.mode match {
+            case Partial => PartialMerge
+            case Complete => Final
+            case other => other
+          }
+          ae.copy(mode = mode)

Review Comment:
   With `twoStage.mode=TOP`, a final wrapper can coexist with an ordinary 
filtered aggregate, such as `SUM(f.x)` alongside `MAX(d.v) FILTER (WHERE 
d.flag)`. This copy changes the ordinary aggregate from `Complete` to `Final` 
but retains its filter. The mapper has already applied that filter and no 
longer outputs `d.flag`. Velox still translates reducer filters in 
`HashAggregateExecTransformer.getAggRelInternal`, so the reference cannot bind 
and native aggregation falls back. Clear filters on the reducer expressions, 
retaining them on the mapper.



##########
gluten-substrait/src/main/scala/org/apache/gluten/extension/joinagg/ImplementJoinAggregate.scala:
##########
@@ -150,16 +179,74 @@ case class ImplementJoinAggregate(spark: SparkSession) 
extends SparkStrategy {
     } else {
       childPlan
     }
+    val stageChild = if (stage == AggregationStage.TWO_STAGE) {
+      buildMapperAggregate(grouping, preparedChild, rewrittenAggExprs)
+    } else {
+      preparedChild
+    }
+    val stageExpressions = if (stage == AggregationStage.TWO_STAGE) {
+      rewrittenAggExprs.map {
+        ae =>
+          val mode = ae.mode match {
+            case Partial => PartialMerge
+            case Complete => Final
+            case other => other
+          }
+          ae.copy(mode = mode)
+      }
+    } else {
+      rewrittenAggExprs
+    }
+    val distribution = stage match {
+      case AggregationStage.LOCAL => None
+      case AggregationStage.DISTRIBUTED | AggregationStage.TWO_STAGE =>
+        Some(grouping.map(_.toAttribute))
+    }
     if (packOutputBuffers) {
-      planBufferPhase(
+      buildBufferAggregate(
         grouping,
         aggregateExpressions,
         resultExpressions,
-        preparedChild,
-        rewrittenAggExprs)
+        stageChild,
+        stageExpressions,
+        distribution)
     } else {
-      planFinalOutput(grouping, resultExpressions, preparedChild, 
rewrittenAggExprs)
+      buildFinalAggregate(grouping, resultExpressions, stageChild, 
stageExpressions, distribution)

Review Comment:
   With `twoStage.mode=TOP`, the mapper outputs grouping attributes and 
aggregate buffers, but the reducer still receives the original grouping 
expressions. For a computed key such as `substr(i_item_desc, 3)`, the reducer 
tries to bind `i_item_desc`, which the mapper no longer outputs. Use the 
grouping attributes for the reducer while retaining the original expressions on 
the mapper.



##########
gluten-substrait/src/main/scala/org/apache/gluten/extension/joinagg/ImplementJoinAggregate.scala:
##########
@@ -150,16 +179,74 @@ case class ImplementJoinAggregate(spark: SparkSession) 
extends SparkStrategy {
     } else {
       childPlan
     }
+    val stageChild = if (stage == AggregationStage.TWO_STAGE) {
+      buildMapperAggregate(grouping, preparedChild, rewrittenAggExprs)

Review Comment:
   With aggregate pushdown enabled, `TOP` also adds this mapper when no join 
was crossed. `PushAggregateThroughJoin.splitAggregate` wraps ordinary 
aggregations regardless of their child, so `SELECT k, SUM(v) FROM t GROUP BY k` 
gets `Partial → PartialMerge → Final`. The extra local merge receives 
already-unique per-partition keys and builds another hash table without 
reducing rows. Restrict mapper insertion to actual pushdown, or skip it when 
the child already performs the same-key local aggregation.



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