Jackie-Jiang commented on code in PR #19302:
URL: https://github.com/apache/pinot/pull/19302#discussion_r3810868285
##########
pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/function/DistinctCountULLAggregationFunctionTest.java:
##########
@@ -34,28 +42,82 @@ public void testCanUseStarTreeDefaultP() {
DistinctCountULLAggregationFunction function = new
DistinctCountULLAggregationFunction(
List.of(ExpressionContext.forIdentifier("col")));
- Assert.assertTrue(function.canUseStarTree(Map.of()));
-
Assert.assertTrue(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
"12")));
-
Assert.assertTrue(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
12)));
-
Assert.assertFalse(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
16)));
+ assertTrue(function.canUseStarTree(Map.of()));
+ assertTrue(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
"12")));
+ assertTrue(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
12)));
+ assertFalse(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
16)));
function = new
DistinctCountULLAggregationFunction(List.of(ExpressionContext.forIdentifier("col"),
ExpressionContext.forLiteral(Literal.intValue(12))));
- Assert.assertTrue(function.canUseStarTree(Map.of()));
-
Assert.assertTrue(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
"12")));
-
Assert.assertTrue(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
12)));
-
Assert.assertFalse(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
"16")));
+ assertTrue(function.canUseStarTree(Map.of()));
+ assertTrue(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
"12")));
+ assertTrue(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
12)));
+ assertFalse(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
"16")));
}
@Test
public void testCanUseStarTreeCustomP() {
DistinctCountULLAggregationFunction function = new
DistinctCountULLAggregationFunction(
List.of(ExpressionContext.forIdentifier("col"),
ExpressionContext.forLiteral(Literal.stringValue("16"))));
- Assert.assertFalse(function.canUseStarTree(Map.of()));
-
Assert.assertFalse(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
"12")));
-
Assert.assertTrue(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
16)));
-
Assert.assertTrue(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
"16")));
+ assertFalse(function.canUseStarTree(Map.of()));
+ assertFalse(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
"12")));
+ assertTrue(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
16)));
+ assertTrue(function.canUseStarTree(Map.of(Constants.HLLPLUS_ULL_P_KEY,
"16")));
+ }
+
+ private static final ExpressionContext COLUMN =
ExpressionContext.forIdentifier("column");
+ private static final long[][] MV_ROWS = {{1L, 2L}, {3L, 4L}, {5L, 6L}, {1L,
3L}};
+ private static final long[] FLATTENED = {1L, 2L, 3L, 4L, 5L, 6L, 1L, 3L};
+
+ private static DistinctCountULLAggregationFunction create() {
+ return new DistinctCountULLAggregationFunction(List.of(COLUMN));
+ }
+
+ private static Map<ExpressionContext, BlockValSet> mvBlock() {
+ return Map.of(COLUMN, SyntheticBlockValSets.LongMV.create(null, MV_ROWS));
Review Comment:
Partly addressed. Both test classes now have a dictionary-encoded MV case,
which was the branch I most agreed was missing — it collects dictionary ids and
resolves them only at extract time, so nothing else covered it. I
mutation-checked both: changing `dictIds[i]` to `dictIds[i][0]` in the MV
dictionary path makes them fail 6 -> 3, so they exercise the branch rather than
passing vacuously.
I have not made them data-driven over all six stored types, and want to be
explicit that this is a judgement call rather than an oversight. The per-type
MV bodies are mechanically identical apart from the accessor and element type,
and covering them needs four more MV fixtures in `SyntheticBlockValSets`
(`IntMV`, `FloatMV`/`DoubleMV`, `StrMV`, `BytesMV`) that nothing else uses
today. End-to-end coverage now comes from `UuidAggregationTest`, which
exercises the `BYTES` stored type over both dictionary-encoded and raw MV
columns. Happy to add the full matrix if a maintainer would rather have it.
##########
pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/function/SegmentPartitionedDistinctCountAggregationFunctionTest.java:
##########
@@ -0,0 +1,98 @@
+/**
+ * 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 java.util.List;
+import java.util.Map;
+import org.apache.pinot.common.request.context.ExpressionContext;
+import org.apache.pinot.core.common.BlockValSet;
+import org.apache.pinot.core.common.SyntheticBlockValSets;
+import org.apache.pinot.core.query.aggregation.AggregationResultHolder;
+import org.apache.pinot.core.query.aggregation.groupby.GroupByResultHolder;
+import
org.apache.pinot.core.query.aggregation.groupby.ObjectGroupByResultHolder;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+
+/// Multi-value column support for `SEGMENTPARTITIONEDDISTINCTCOUNT`.
+///
+/// This function used to read the single-value accessors unconditionally, so
a multi-value column was not something
+/// it could aggregate at all. It now branches on
`BlockValSet.isSingleValue()` the way the HyperLogLog and bitmap
+/// families already did. Its counts are exact, so the answers are asserted
directly rather than as estimates.
+public class SegmentPartitionedDistinctCountAggregationFunctionTest {
+ private static final ExpressionContext COLUMN =
ExpressionContext.forIdentifier("column");
+ private static final long[][] MV_ROWS = {{1L, 2L}, {3L, 4L}, {5L, 6L}, {1L,
3L}};
+ private static final long[] FLATTENED = {1L, 2L, 3L, 4L, 5L, 6L, 1L, 3L};
+
+ private static SegmentPartitionedDistinctCountAggregationFunction create() {
+ return new
SegmentPartitionedDistinctCountAggregationFunction(List.of(COLUMN));
+ }
+
+ private static Map<ExpressionContext, BlockValSet> mvBlock() {
+ return Map.of(COLUMN, SyntheticBlockValSets.LongMV.create(null, MV_ROWS));
Review Comment:
Partly addressed. Both test classes now have a dictionary-encoded MV case,
which was the branch I most agreed was missing — it collects dictionary ids and
resolves them only at extract time, so nothing else covered it. I
mutation-checked both: changing `dictIds[i]` to `dictIds[i][0]` in the MV
dictionary path makes them fail 6 -> 3, so they exercise the branch rather than
passing vacuously.
I have not made them data-driven over all six stored types, and want to be
explicit that this is a judgement call rather than an oversight. The per-type
MV bodies are mechanically identical apart from the accessor and element type,
and covering them needs four more MV fixtures in `SyntheticBlockValSets`
(`IntMV`, `FloatMV`/`DoubleMV`, `StrMV`, `BytesMV`) that nothing else uses
today. End-to-end coverage now comes from `UuidAggregationTest`, which
exercises the `BYTES` stored type over both dictionary-encoded and raw MV
columns. Happy to add the full matrix if a maintainer would rather have it.
##########
pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/function/SegmentPartitionedDistinctCountAggregationFunction.java:
##########
@@ -72,7 +72,14 @@ public GroupByResultHolder createGroupByResultHolder(int
initialCapacity, int ma
public void aggregate(int length, AggregationResultHolder
aggregationResultHolder,
Map<ExpressionContext, BlockValSet> blockValSetMap) {
BlockValSet blockValSet = blockValSetMap.get(_expression);
+ if (blockValSet.isSingleValue()) {
+ aggregateSV(length, aggregationResultHolder, blockValSet);
+ } else {
+ aggregateMV(length, aggregationResultHolder, blockValSet);
Review Comment:
I tried this and then backed it out, so recording the reason rather than
silently declining.
Adding `SEGMENTPARTITIONEDDISTINCTCOUNT` to `UuidAggregationTest` does pass
— the fixture overrides `getNumAvroFiles()` to 1, so there is a single segment
and the per-segment sum equals an exact distinct count. But the function's
contract requires values to be non-overlapping across segments, and this
fixture violates that: `UUID_0` appears twice in the single-value column and in
two separate multi-value rows. The assertion would therefore encode a
coincidence of the segment layout, and would start failing if anyone changed
that override to 2 — for a reason having nothing to do with multi-value support.
Its MV paths are covered directly by the new unit test instead, including
the dictionary-id branch. An integration test that genuinely exercises this
function wants a fixture built to satisfy its partitioning premise, which seems
better as its own change than bolted onto the UUID test.
--
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]