yashmayya commented on code in PR #19972:
URL: https://github.com/apache/pinot/pull/19972#discussion_r4329890095


##########
pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/function/AggregationFunction.java:
##########
@@ -316,6 +316,18 @@ default FinalResult mergeFinalResult(FinalResult 
finalResult1, FinalResult final
     throw new UnsupportedOperationException("Cannot merge final results for 
function: " + getType());
   }
 
+  /// Returns whether [#extractFinalResult] has returned an approximate result 
for a function that can also answer
+  /// exactly. The SMART functions start exact and switch a group to a sketch 
once it crosses their conversion
+  /// threshold. A merge with a sketch always returns a sketch, so the 
extraction sees the switch, and records it here.
+  /// Read it after extracting, to report the result as approximate.
+  ///
+  /// A function instance belongs to one query, and so does the flag. Group 
trimming also extracts final results, so a
+  /// group that is trimmed away can still set it. Functions that are always 
exact or always approximate keep the
+  /// default.
+  default boolean hasApproximatedResult() {

Review Comment:
   Agreed that one choke point (for example `QueryThreadContext`) would be 
better and would also cover gapfill. I am keeping this PR as it is and leaving 
that as a follow-up.



##########
pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/function/BaseDistinctCountSmartSketchAggregationFunction.java:
##########
@@ -52,11 +52,19 @@ abstract class 
BaseDistinctCountSmartSketchAggregationFunction
   // Use empty IntOpenHashSet as a placeholder for empty result
   protected static final IntSet EMPTY_PLACEHOLDER = new IntOpenHashSet();
 
+  /// Set by `extractFinalResult` when it reads a sketch, see 
[AggregationFunction#hasApproximatedResult()].
+  protected volatile boolean _approximatedResult;

Review Comment:
   Done in d704f8cf42: the SMART functions now read the flag before they write 
it.



##########
pinot-core/src/main/java/org/apache/pinot/core/query/reduce/ExecutionStatsAggregator.java:
##########
@@ -296,6 +298,9 @@ public void setStats(String rawTableName, 
BrokerResponseNative brokerResponseNat
     brokerResponseNative.setGroupsTrimmed(_groupsTrimmed);
     brokerResponseNative.setNumGroupsLimitReached(_numGroupsLimitReached);
     
brokerResponseNative.setNumGroupsWarningLimitReached(_numGroupsWarningLimitReached);
+    if (_approximatedResult) {

Review Comment:
   Done: it now sets the flag directly, like its neighbors.



##########
pinot-core/src/main/java/org/apache/pinot/core/operator/blocks/results/GroupByResultsBlock.java:
##########
@@ -237,6 +238,10 @@ public Map<String, String> getResultsMetadata() {
     if (_numGroupsWarningLimitReached) {
       metadata.put(MetadataKey.NUM_GROUPS_WARNING_LIMIT_REACHED.getName(), 
"true");
     }
+    // The combine step has already extracted the final results when the 
server returns them.

Review Comment:
   Done: the comment now says that ORDER BY trimming also extracts final 
results, also for groups that it trims away.



##########
pinot-core/src/test/java/org/apache/pinot/core/operator/blocks/results/AggregationResultsBlockTest.java:
##########
@@ -0,0 +1,61 @@
+/**
+ * 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.blocks.results;
+
+import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.apache.pinot.common.datatable.DataTable;
+import org.apache.pinot.common.datatable.DataTable.MetadataKey;
+import org.apache.pinot.core.query.aggregation.function.AggregationFunction;
+import org.apache.pinot.core.query.request.context.QueryContext;
+import 
org.apache.pinot.core.query.request.context.utils.QueryContextConverterUtils;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+
+public class AggregationResultsBlockTest {

Review Comment:
   Done.



##########
pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/function/SmartFunctionApproximatedResultTest.java:
##########
@@ -0,0 +1,83 @@
+/**
+ * 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.query.aggregation.function;
+
+import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
+import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
+import java.util.List;
+import org.apache.pinot.common.request.Literal;
+import org.apache.pinot.common.request.context.ExpressionContext;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+
+/// Covers [AggregationFunction#hasApproximatedResult()] for the SMART 
functions: extracting an exact accumulator leaves
+/// it unset, and extracting one that a merge switched to a sketch sets it.
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class SmartFunctionApproximatedResultTest {
+  private static final ExpressionContext COLUMN = 
ExpressionContext.forIdentifier("col");
+  private static final ExpressionContext THRESHOLD_ONE =
+      ExpressionContext.forLiteral(Literal.stringValue("threshold=1"));
+
+  @DataProvider
+  public static Object[][] distinctCountFunctions() {
+    List<ExpressionContext> arguments = List.of(COLUMN, THRESHOLD_ONE);
+    return new Object[][]{
+        {new DistinctCountSmartHLLAggregationFunction(arguments, false)},
+        {new DistinctCountSmartHLLPlusAggregationFunction(arguments, false)},
+        {new DistinctCountSmartULLAggregationFunction(arguments, false)}
+    };
+  }
+
+  @Test(dataProvider = "distinctCountFunctions")
+  public void testDistinctCount(AggregationFunction function) {
+    assertEquals(function.extractFinalResult(null), 0);
+    assertEquals(function.extractFinalResult(new IntOpenHashSet(new 
int[]{1})), 1);
+    assertFalse(function.hasApproximatedResult());
+
+    // Two values cross the threshold of one, so the merge switches the 
accumulator to a sketch.
+    Object merged = function.merge(new IntOpenHashSet(new int[]{1}), new 
IntOpenHashSet(new int[]{2}));
+    function.extractFinalResult(merged);
+    assertTrue(function.hasApproximatedResult());
+  }
+
+  @Test
+  public void testPercentile() {
+    PercentileSmartTDigestAggregationFunction function = new 
PercentileSmartTDigestAggregationFunction(
+        List.of(COLUMN, 
ExpressionContext.forLiteral(Literal.doubleValue(50.0)), THRESHOLD_ONE), false);
+    function.extractFinalResult(null);

Review Comment:
   Done: it now asserts the `Double.NEGATIVE_INFINITY` default.



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