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


##########
gluten-substrait/src/main/scala/org/apache/gluten/extension/joinagg/ImplementJoinAggregate.scala:
##########
@@ -150,16 +179,75 @@ 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
+          }
+          // Like Spark's AggUtils.mayRemoveAggFilters, remove filters from 
buffer-merge stages.
+          ae.copy(mode = mode, filter = None)
+      }
+    } 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 receives the original grouping expressions. 
For a computed key such as `substr(w_warehouse_name, 1, 20)`, the reducer 
references `w_warehouse_name` after the mapper has dropped it, causing an 
input-binding failure. Pass `grouping.map(_.toAttribute)` to the reducer in 
TWO_STAGE mode so only the mapper evaluates the original expressions.



##########
gluten-substrait/src/main/scala/org/apache/gluten/extension/joinagg/ImplementJoinAggregate.scala:
##########
@@ -150,16 +179,75 @@ 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

Review Comment:
   With `twoStage.mode=TOP`, an unwrapped imperative aggregate such as Spark's 
`approx_count_distinct` changes from `Complete` to `Final`. The mapper prefixes 
its buffers with grouping columns, but `buildFinalAggregate` still uses 
`initialInputBufferOffset = 0`. Spark's imperative merge reads buffers 
positionally, so grouped queries consume the wrong columns when executed in 
Spark, including fallback. Pass `grouping.size` as the reducer's input-buffer 
offset for TWO_STAGE mode, preserving the existing offset for other stages. Add 
a grouped SUM + approx_count_distinct regression test that exercises Spark 
aggregation without native HLL rewriting.



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