rohityadav1993 commented on code in PR #19120:
URL: https://github.com/apache/pinot/pull/19120#discussion_r4378283946


##########
pinot-core/src/main/java/org/apache/pinot/core/operator/InstanceResponseOperator.java:
##########
@@ -116,14 +124,14 @@ protected BaseResultsBlock getBaseBlock() {
 
     BaseResultsBlock resultsBlock = getCombinedResults();
 
-    long mainThreadCpuTimeNs = resourceSnapshot.getCpuTimeNs();
-    long mainThreadMemAllocatedBytes = resourceSnapshot.getAllocatedBytes();
-
-    long totalWallClockTimeNs = System.nanoTime() - startWallClockTimeNs;
+    _mainThreadCpuTimeNs += resourceSnapshot.getCpuTimeNs();

Review Comment:
   Added to the description. "No behavior change when the option is off" now 
names this as the one exception: the consumer-thread CPU and allocation stats 
are summed over all streamed blocks for every streaming combine, not only this 
one. "Thread CPU and allocation stats" now says `systemActivitiesCpuTimeNs` is 
a lower bound, because the time blocked in the send is excluded.



##########
pinot-spi/src/main/java/org/apache/pinot/spi/utils/CommonConstants.java:
##########
@@ -1698,6 +1711,53 @@ public enum AndRestrictionPushdownMode {
     // Sequential combine utilizes N + 1 threads, N for processing and 1 for 
merge. Pair-wise only uses N.
     public static final int 
DEFAULT_SORT_AGGREGATE_SEQUENTIAL_COMBINE_NUM_SEGMENTS_THRESHOLD =
         Runtime.getRuntime().availableProcessors();
+
+    /// Selects the streaming k-way-merge selection ORDER BY combine
+    /// ([Broker.Request.QueryOptionKey#SORTED_SELECTION_MERGE_MODE]).
+    ///
+    /// The merge runs single-threaded on the consumer thread, so it trades 
`maxExecutionThreads` worth of parallel
+    /// segment processing for the ability to emit sorted blocks 
incrementally. That trade only pays off when the
+    /// segments are physically sorted on the leading ORDER BY column, since 
an unsorted child must do a full scan
+    /// plus top-K synchronously before the merge can take its first row.
+    public enum SortedSelectionMergeMode {
+      /// Never use the streaming merge. Selection ORDER BY keeps its existing 
combine operators.
+      OFF,
+      /// Always use the streaming merge, including when the leading ORDER BY 
expression is not an identifier and no
+      /// segment is sorted. Children then materialize their top-K eagerly and 
the merge is strictly slower than
+      /// [#OFF]; intended for benchmarking and A/B, not for production 
traffic.
+      ON,
+      /// Use the streaming merge only when at least
+      /// 
[Broker.Request.QueryOptionKey#SORTED_SELECTION_MERGE_AUTO_MIN_SORTED_RATIO] of 
the queried segments are
+      /// physically sorted on the leading ORDER BY column. Decided from 
segment metadata alone, without acquiring
+      /// any segment.
+      AUTO

Review Comment:
   Done in 91386dcdfd. The `AUTO` Javadoc now says it is experimental like 
`ON`: the default ratio is not measured, and the check ignores segment size and 
overlap (#19924). The `sortedSelectionMergeMode` query option Javadoc and the 
options table in the description say the same.



##########
pinot-core/src/main/java/org/apache/pinot/core/operator/query/StreamingSelectionOrderByOperator.java:
##########
@@ -0,0 +1,620 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pinot.core.operator.query;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.CaseFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.PriorityQueue;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+import org.apache.pinot.common.request.context.ExpressionContext;
+import org.apache.pinot.common.request.context.OrderByExpressionContext;
+import org.apache.pinot.common.utils.DataSchema;
+import org.apache.pinot.common.utils.HashUtil;
+import org.apache.pinot.core.common.BlockValSet;
+import org.apache.pinot.core.common.Operator;
+import org.apache.pinot.core.common.RowBasedBlockValueFetcher;
+import org.apache.pinot.core.operator.BaseOperator;
+import org.apache.pinot.core.operator.BaseProjectOperator;
+import org.apache.pinot.core.operator.BitmapDocIdSetOperator;
+import org.apache.pinot.core.operator.ColumnContext;
+import org.apache.pinot.core.operator.ExecutionStatistics;
+import org.apache.pinot.core.operator.ExplainAttributeBuilder;
+import org.apache.pinot.core.operator.ProjectionOperator;
+import org.apache.pinot.core.operator.ProjectionOperatorUtils;
+import org.apache.pinot.core.operator.blocks.ValueBlock;
+import org.apache.pinot.core.operator.blocks.results.SelectionResultsBlock;
+import org.apache.pinot.core.operator.transform.TransformOperator;
+import 
org.apache.pinot.core.operator.transform.function.TransformFunctionFactory;
+import org.apache.pinot.core.query.request.context.QueryContext;
+import org.apache.pinot.core.query.selection.SelectionOperatorUtils;
+import org.apache.pinot.core.query.utils.OrderByComparatorFactory;
+import org.apache.pinot.segment.spi.IndexSegment;
+import org.apache.pinot.segment.spi.datasource.DataSource;
+import org.apache.pinot.spi.query.QueryScanCostContext;
+import org.roaringbitmap.RoaringBitmap;
+
+
+/// Lazy, incremental selection ORDER BY operator for segments that are 
physically sorted on the first order-by column.
+///
+/// Unlike [SelectionOrderByOperator] (which materializes the segment's whole 
top-K in a single block) this
+/// operator emits one globally-sorted [SelectionResultsBlock] per 
[#getNextBlock()] call and returns
+/// `null` when the segment is exhausted, so that a downstream k-way-merge 
combine operator can pull from many
+/// segments lazily and stop early. It relies on the underlying project 
operator iterating the first order-by column in
+/// the query order (the caller must guarantee 
`projectOperator.isCompatibleWith(DocIdOrder.fromAsc(asc))`).
+///
+/// Every instance emits at least one block before `null`: a segment matching 
no rows emits a single empty block
+/// carrying the [DataSchema], so consumers never have to reconstruct a schema 
the segment already knows.
+///
+/// It runs in one of two emission modes:
+///
+/// - **No tail to sort** (`numSortedExpressions == numOrderByExpressions`, 
e.g. `ORDER BY sorted`):
+///   rows already arrive from the project operator in final order, so each 
call emits the next project block
+///   (trimmed to the remaining `limit + offset` budget).
+/// - **Tail to sort** (`numSortedExpressions < numOrderByExpressions`, e.g.
+///   `ORDER BY sorted, other`):
+///   each call reads forward until a value of the sorted prefix changes (a 
"run": rows that tie on every sorted
+///   order-by column), retains the run's top rows by the unsorted tail, as 
many as the remaining `limit + offset`
+///   budget allows, and emits them sorted. This bounds the in-memory run 
buffer to `limit + offset` rows even when
+///   the sorted prefix is near-constant (very low cardinality).
+///
+/// Like [SelectionOrderByOperator] it preserves the two-phase projection 
optimization: when there are output

Review Comment:
   Done in 91386dcdfd, with one change: #20003 removed 
`lateMaterializeSortedOrderBy` (late materialization is now always on for the 
materialized path), so this PR is now rebased on it. The class Javadoc now says 
the two-phase fetch is the operator's own and needs no query option, and that 
the materialized sorted-prefix operators late-materialize the same way since 
#20003. Agreed on the three copies of the payload fetch 
(`SelectionOrderByOperator`, `LinearSelectionOrderByOperator` and this 
operator). The shared helper in #19923 (A2) will start from 
`LinearSelectionOrderByOperator`'s version.



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