xiangfu0 commented on code in PR #19264:
URL: https://github.com/apache/pinot/pull/19264#discussion_r4148021602


##########
pinot-core/src/main/java/org/apache/pinot/core/util/GroupByUtils.java:
##########
@@ -87,6 +98,125 @@ public static GroupByResultsBlock 
buildGroupingSetsResultsBlock(QueryContext que
     return resultsBlock;
   }
 
+  /// Builds the segment-level [GroupByResultsBlock] for a grouping-set query 
from BASE groups, i.e. groups
+  /// aggregated once over the union of all grouping-set columns (a plain 
GROUP BY), rather than by expanding
+  /// every input row into one group per grouping set. Each base group is then 
projected into each grouping set:
+  /// its rolled-up (non-participating) columns are set to `null`, the 
`$groupingId` discriminator is appended,
+  /// and the base group's aggregation intermediates are merged into the 
derived group. This moves the per-set
+  /// fan-out from O(rows) to O(base groups), reusing the fast plain-GROUP-BY 
scan path.
+  ///
+  /// Because a base group's intermediate result flows into every grouping 
set, and [AggregationFunction#merge]
+  /// mutates its first argument, each base intermediate is cloned per set 
before it becomes a merge target (see
+  /// [#cloneIntermediate]). This keeps the derivation exact for object-backed 
accumulators (AVG, DISTINCTCOUNT,
+  /// percentiles, ...) as well as scalar ones.
+  ///
+  /// @param discriminatorColumnIndex index of the synthetic $groupingId 
column, i.e. the number of union
+  ///                                 group-by columns
+  public static GroupByResultsBlock 
buildGroupingSetsResultsBlockFromBaseGroups(QueryContext queryContext,
+      DataSchema dataSchema, AggregationGroupByResult baseResult, int 
discriminatorColumnIndex,
+      boolean numGroupsLimitReached, boolean numGroupsWarningLimitReached) {
+    AggregationFunction[] aggregationFunctions = 
queryContext.getAggregationFunctions();
+    assert aggregationFunctions != null;
+    int numAggregationFunctions = aggregationFunctions.length;
+    List<int[]> groupingSets = queryContext.getGroupingSets();
+    int numSets = groupingSets.size();
+    int numUnionColumns = discriminatorColumnIndex;
+    // Per grouping set: membership mask over the union columns (true = 
participates, false = rolled up to NULL).
+    boolean[][] setContains = new boolean[numSets][numUnionColumns];
+    for (int s = 0; s < numSets; s++) {
+      for (int columnIndex : groupingSets.get(s)) {
+        setContains[s][columnIndex] = true;
+      }
+    }
+
+    // Derived group table keyed on (projected union values..., $groupingId). 
Values layout mirrors the record
+    // schema: key columns first, then the aggregation intermediates.
+    Map<Key, Record> derived = new HashMap<>();

Review Comment:
   Fixed in a9b179e. When base groups × sets can exceed max(numGroupsLimit, 
numSets), derivation now processes sets coarsest-first into one capped map 
instead of materializing every per-set map first. It continues merging into 
admitted groups after the cap fills, and the mixed BASE/FULL merge cannot grow 
past the same cap. Dropped groups set groupsTrimmed and numGroupsLimitReached; 
the retained derived count also participates in the warning-limit flag. Focused 
derive/mixed-layout/streaming tests passed 9/9 locally (with the local compiler 
classpath workaround documented in the PR body); exact-head CI is pending.



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