This is an automated email from the ASF dual-hosted git repository.
karan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git
The following commit(s) were added to refs/heads/master by this push:
new 6707757e974 ShimCursor: Fix dimension selectors on non-strings.
(#18371)
6707757e974 is described below
commit 6707757e9742342f24b3857777b1d904dff41807
Author: Gian Merlino <[email protected]>
AuthorDate: Wed Aug 6 04:06:37 2025 -0700
ShimCursor: Fix dimension selectors on non-strings. (#18371)
Follow-up to #18305. Fixes a bug where calling ShimCursor's
makeDimensionSelector on a non-string type would throw an error.
Now, it has behavior similar to QueryableIndexCursor:
- Uses ValueTypes.makeNumericWrappingDimensionSelector on numeric types,
casting the numbers to strings.
- Returns a nil selector for array and complex types.
The new tests verify selector compatibility more extensively.
---
.../segment/shim/ShimColumnSelectorFactory.java | 52 +-
.../apache/druid/segment/shim/ShimCursorTest.java | 530 +++++++++++++++------
2 files changed, 423 insertions(+), 159 deletions(-)
diff --git
a/processing/src/main/java/org/apache/druid/segment/shim/ShimColumnSelectorFactory.java
b/processing/src/main/java/org/apache/druid/segment/shim/ShimColumnSelectorFactory.java
index 5b0029c3c57..2fd84b62625 100644
---
a/processing/src/main/java/org/apache/druid/segment/shim/ShimColumnSelectorFactory.java
+++
b/processing/src/main/java/org/apache/druid/segment/shim/ShimColumnSelectorFactory.java
@@ -29,6 +29,7 @@ import org.apache.druid.segment.DimensionSelector;
import org.apache.druid.segment.NilColumnValueSelector;
import org.apache.druid.segment.column.ColumnCapabilities;
import org.apache.druid.segment.column.ValueType;
+import org.apache.druid.segment.column.ValueTypes;
import org.apache.druid.segment.vector.MultiValueDimensionVectorSelector;
import org.apache.druid.segment.vector.SingleValueDimensionVectorSelector;
import org.apache.druid.segment.vector.VectorObjectSelector;
@@ -57,28 +58,49 @@ public class ShimColumnSelectorFactory implements
ColumnSelectorFactory
return dimensionSelectors.computeIfAbsent(
dimensionSpec,
spec -> {
- if (spec.mustDecorate()) {
+ if (spec.mustDecorate() || spec.getExtractionFn() != null) {
throw DruidException.defensive("Only non-decorated dimensions can
be vectorized.");
}
- final ColumnCapabilities capabilities =
cursor.vectorColumnSelectorFactory
- .getColumnCapabilities(dimensionSpec.getDimension());
+
+ final String columnName = dimensionSpec.getDimension();
+ final ColumnCapabilities capabilities =
cursor.vectorColumnSelectorFactory.getColumnCapabilities(columnName);
+
if (capabilities == null) {
return DimensionSelector.nilSelector();
- } else if
(ColumnProcessors.useDictionaryEncodedSelector(capabilities)) {
- if (capabilities.hasMultipleValues().isMaybeTrue()) {
- final MultiValueDimensionVectorSelector vectorSelector =
-
cursor.vectorColumnSelectorFactory.makeMultiValueDimensionSelector(spec);
- return new ShimMultiValueDimensionSelector(cursor,
vectorSelector);
+ } else if (capabilities.is(ValueType.STRING)) {
+ if (ColumnProcessors.useDictionaryEncodedSelector(capabilities)) {
+ // Dictionary-encoded string column.
+ if (capabilities.hasMultipleValues().isMaybeTrue()) {
+ final MultiValueDimensionVectorSelector vectorSelector =
+
cursor.vectorColumnSelectorFactory.makeMultiValueDimensionSelector(spec);
+ return new ShimMultiValueDimensionSelector(cursor,
vectorSelector);
+ } else {
+ final SingleValueDimensionVectorSelector vectorSelector =
+
cursor.vectorColumnSelectorFactory.makeSingleValueDimensionSelector(spec);
+ return new ShimSingleValueDimensionSelector(cursor,
vectorSelector);
+ }
} else {
- final SingleValueDimensionVectorSelector vectorSelector =
-
cursor.vectorColumnSelectorFactory.makeSingleValueDimensionSelector(spec);
- return new ShimSingleValueDimensionSelector(cursor,
vectorSelector);
+ // Non-dictionary encoded string column. Possibly an expression
virtual column.
+ final VectorObjectSelector vectorObjectSelector =
+
cursor.vectorColumnSelectorFactory.makeObjectSelector(spec.getDimension());
+ return new ShimVectorObjectDimSelector(
+ cursor,
+ vectorObjectSelector,
+ capabilities.hasMultipleValues().isMaybeTrue()
+ );
}
+ } else if (capabilities.isNumeric()) {
+ // Caller requested a dimension selector on top of a numeric
column.
+ return ValueTypes.makeNumericWrappingDimensionSelector(
+ capabilities.getType(),
+ makeColumnValueSelector(columnName),
+ null /* No extractionFn; we checked above that extractionFn is
not present. */
+ );
} else {
- // Non-dictionary encoded column, like virtual columns.
- VectorObjectSelector vectorObjectSelector =
-
cursor.vectorColumnSelectorFactory.makeObjectSelector(spec.getDimension());
- return new ShimVectorObjectDimSelector(cursor,
vectorObjectSelector, capabilities.hasMultipleValues().isMaybeTrue());
+ // Array or complex. Callers should be calling
makeColumnValueSelector instead for these types. If they do
+ // call makeDimensionSelector for some reason, give them a column
full of nulls, since that's what
+ // QueryableIndexColumnSelectorFactory would do.
+ return DimensionSelector.nilSelector();
}
}
);
diff --git
a/processing/src/test/java/org/apache/druid/segment/shim/ShimCursorTest.java
b/processing/src/test/java/org/apache/druid/segment/shim/ShimCursorTest.java
index e915e196ce8..2891d402de9 100644
--- a/processing/src/test/java/org/apache/druid/segment/shim/ShimCursorTest.java
+++ b/processing/src/test/java/org/apache/druid/segment/shim/ShimCursorTest.java
@@ -19,15 +19,19 @@
package org.apache.druid.segment.shim;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
+import it.unimi.dsi.fastutil.ints.IntList;
import org.apache.druid.data.input.MapBasedInputRow;
import org.apache.druid.data.input.impl.DimensionsSpec;
import org.apache.druid.java.util.common.ISE;
+import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.java.util.common.io.Closer;
import org.apache.druid.math.expr.ExpressionProcessing;
import org.apache.druid.query.QueryContext;
import org.apache.druid.query.QueryContexts;
import org.apache.druid.query.dimension.DefaultDimensionSpec;
import org.apache.druid.query.expression.TestExprMacroTable;
+import org.apache.druid.segment.AutoTypeColumnSchema;
import org.apache.druid.segment.ColumnSelectorFactory;
import org.apache.druid.segment.ColumnValueSelector;
import org.apache.druid.segment.Cursor;
@@ -40,19 +44,20 @@ import org.apache.druid.segment.TestIndex;
import org.apache.druid.segment.VirtualColumns;
import org.apache.druid.segment.column.ColumnCapabilities;
import org.apache.druid.segment.column.ColumnType;
-import org.apache.druid.segment.data.IndexedInts;
+import org.apache.druid.segment.column.ValueType;
import org.apache.druid.segment.incremental.IncrementalIndex;
import org.apache.druid.segment.incremental.IncrementalIndexSchema;
import org.apache.druid.segment.incremental.OnheapIncrementalIndex;
import org.apache.druid.segment.vector.VectorCursor;
import org.apache.druid.segment.virtual.ExpressionVirtualColumn;
+import org.hamcrest.CoreMatchers;
import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.runners.Parameterized;
+import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
@@ -61,6 +66,12 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
/**
* Compares the results between using a {@link ShimCursor} and {@link Cursor}
*/
@@ -71,7 +82,7 @@ public class ShimCursorTest
}
@Parameterized.Parameters
- public static Collection<Object> data()
+ public static Collection<Object> vectorSizes()
{
return List.of(1, 2, 4, 7, 512);
}
@@ -93,24 +104,37 @@ public class ShimCursorTest
/**
* Tests long and double columns.
*/
- @ParameterizedTest(name = "Number columns with vector size {0}")
- @MethodSource("data")
+ @ParameterizedTest(name = "vectorSize = {0}")
+ @MethodSource("vectorSizes")
public void testNumberColumns(int vectorSize)
{
- IncrementalIndex incrementalIndex = closer.register(new
OnheapIncrementalIndex.Builder()
- .setMaxRowCount(100)
- .setIndexSchema(
- IncrementalIndexSchema.builder()
- .withDimensionsSpec(
- DimensionsSpec.builder()
- .useSchemaDiscovery(true)
-
.setIncludeAllDimensions(true)
- .build()
- )
- .withRollup(false)
- .build()
- )
- .build());
+ IncrementalIndex incrementalIndex = closer.register(
+ new OnheapIncrementalIndex.Builder()
+ .setMaxRowCount(100)
+ .setIndexSchema(
+ IncrementalIndexSchema
+ .builder()
+ .withDimensionsSpec(
+ DimensionsSpec.builder()
+ .useSchemaDiscovery(true)
+ .setIncludeAllDimensions(true)
+ .setDimensions(
+ List.of(
+ new AutoTypeColumnSchema("A",
null),
+ // set B to DOUBLE to avoid
mixed types, which causes the base nonvector
+ // and vector selectors to
return different objects
+ new AutoTypeColumnSchema("B",
ColumnType.DOUBLE),
+ new AutoTypeColumnSchema("C",
null)
+
+ )
+ )
+ .build()
+ )
+ .withRollup(false)
+ .build()
+ )
+ .build()
+ );
final List<String> signature = List.of("A", "B", "C");
@@ -124,7 +148,8 @@ public class ShimCursorTest
incrementalIndex.add(autoRow(signature, Long.MAX_VALUE, -824.0f,
Long.MIN_VALUE));
incrementalIndex.add(autoRow(signature, -1, -2.0d, 112));
- final SimpleQueryableIndex index = closer.register((SimpleQueryableIndex)
TestIndex.persistAndMemoryMap(incrementalIndex));
+ final SimpleQueryableIndex index =
+ closer.register((SimpleQueryableIndex)
TestIndex.persistAndMemoryMap(incrementalIndex));
final QueryableIndexCursorFactory queryableIndexCursorFactory = new
QueryableIndexCursorFactory(index);
CursorBuildSpec cursorBuildSpec = CursorBuildSpec.builder()
@@ -135,7 +160,7 @@ public class ShimCursorTest
)
.build();
CursorHolder cursorHolder =
closer.register(queryableIndexCursorFactory.makeCursorHolder(cursorBuildSpec));
- Assertions.assertTrue(cursorHolder.canVectorize());
+ assertTrue(cursorHolder.canVectorize());
VectorCursor vectorCursor = cursorHolder.asVectorCursor();
Cursor cursor = cursorHolder.asCursor();
@@ -147,24 +172,39 @@ public class ShimCursorTest
/**
* Tests a few dictionary encoded columns, with a few number columns thrown
in.
*/
- @ParameterizedTest(name = "Number columns with vector size {0}")
- @MethodSource("data")
+ @ParameterizedTest(name = "vectorSize = {0}")
+ @MethodSource("vectorSizes")
public void testDictionaryColumns(int vectorSize)
{
- IncrementalIndex incrementalIndex = closer.register(new
OnheapIncrementalIndex.Builder()
- .setMaxRowCount(100)
- .setIndexSchema(
- IncrementalIndexSchema.builder()
- .withDimensionsSpec(
- DimensionsSpec.builder()
- .useSchemaDiscovery(true)
-
.setIncludeAllDimensions(true)
- .build()
- )
- .withRollup(false)
- .build()
- )
- .build());
+ IncrementalIndex incrementalIndex = closer.register(
+ new OnheapIncrementalIndex.Builder()
+ .setMaxRowCount(100)
+ .setIndexSchema(
+ IncrementalIndexSchema
+ .builder()
+ .withDimensionsSpec(
+ DimensionsSpec.builder()
+ .useSchemaDiscovery(false)
+ .setIncludeAllDimensions(true)
+ .setDimensions(
+ List.of(
+ new AutoTypeColumnSchema("A",
null),
+ // set B to DOUBLE to avoid
mixed types, which causes the base nonvector
+ // and vector selectors to
return different objects
+ new AutoTypeColumnSchema("B",
ColumnType.DOUBLE),
+ new AutoTypeColumnSchema("C",
null),
+ new AutoTypeColumnSchema("D",
null),
+ new AutoTypeColumnSchema("E",
null),
+ new AutoTypeColumnSchema("F",
null)
+ )
+ )
+ .build()
+ )
+ .withRollup(false)
+ .build()
+ )
+ .build()
+ );
final List<String> signature = List.of("A", "B", "C", "D", "E", "F");
@@ -176,7 +216,8 @@ public class ShimCursorTest
incrementalIndex.add(autoRow(signature, 6, -1, "Cat", arr(), obj("Bat",
"Knife"), null));
incrementalIndex.add(autoRow(signature, 7, -2.0, "Drew", arr("Machine",
"Rabbit"), obj("bat", "knife"), null));
- final SimpleQueryableIndex index = closer.register((SimpleQueryableIndex)
TestIndex.persistAndMemoryMap(incrementalIndex));
+ final SimpleQueryableIndex index =
+ closer.register((SimpleQueryableIndex)
TestIndex.persistAndMemoryMap(incrementalIndex));
final QueryableIndexCursorFactory queryableIndexCursorFactory = new
QueryableIndexCursorFactory(index);
CursorBuildSpec cursorBuildSpec = CursorBuildSpec.builder()
@@ -187,7 +228,7 @@ public class ShimCursorTest
)
.build();
CursorHolder cursorHolder =
closer.register(queryableIndexCursorFactory.makeCursorHolder(cursorBuildSpec));
- Assertions.assertTrue(cursorHolder.canVectorize());
+ assertTrue(cursorHolder.canVectorize());
VectorCursor vectorCursor = cursorHolder.asVectorCursor();
Cursor cursor = cursorHolder.asCursor();
@@ -196,24 +237,26 @@ public class ShimCursorTest
compareCursors(signature, cursor, shimCursor);
}
- @ParameterizedTest(name = "Non dict-encoded string columns with vector size
{0}")
- @MethodSource("data")
+ @ParameterizedTest(name = "vectorSize = {0}")
+ @MethodSource("vectorSizes")
public void testMultiDimColumns(int vectorSize)
{
- IncrementalIndex incrementalIndex = closer.register(new
OnheapIncrementalIndex.Builder()
- .setMaxRowCount(100)
- .setIndexSchema(
- IncrementalIndexSchema.builder()
- .withDimensionsSpec(
- DimensionsSpec.builder()
- .useSchemaDiscovery(false)
-
.setIncludeAllDimensions(true)
- .build()
- )
- .withRollup(false)
- .build()
- )
- .build());
+ IncrementalIndex incrementalIndex = closer.register(
+ new OnheapIncrementalIndex.Builder()
+ .setMaxRowCount(100)
+ .setIndexSchema(
+ IncrementalIndexSchema.builder()
+ .withDimensionsSpec(
+ DimensionsSpec.builder()
+
.useSchemaDiscovery(false)
+
.setIncludeAllDimensions(true)
+ .build()
+ )
+ .withRollup(false)
+ .build()
+ )
+ .build()
+ );
final List<String> signature = List.of("A", "B");
@@ -225,7 +268,8 @@ public class ShimCursorTest
incrementalIndex.add(autoRow(signature, 6, arr()));
incrementalIndex.add(autoRow(signature, 7, arr("Machine", "Rabbit")));
- final SimpleQueryableIndex index = closer.register((SimpleQueryableIndex)
TestIndex.persistAndMemoryMap(incrementalIndex));
+ final SimpleQueryableIndex index = closer.register((SimpleQueryableIndex)
TestIndex.persistAndMemoryMap(
+ incrementalIndex));
final QueryableIndexCursorFactory queryableIndexCursorFactory = new
QueryableIndexCursorFactory(index);
CursorBuildSpec cursorBuildSpec = CursorBuildSpec.builder()
@@ -236,7 +280,7 @@ public class ShimCursorTest
)
.build();
CursorHolder cursorHolder =
closer.register(queryableIndexCursorFactory.makeCursorHolder(cursorBuildSpec));
- Assertions.assertTrue(cursorHolder.canVectorize());
+ assertTrue(cursorHolder.canVectorize());
VectorCursor vectorCursor = cursorHolder.asVectorCursor();
Cursor cursor = cursorHolder.asCursor();
@@ -246,32 +290,35 @@ public class ShimCursorTest
}
@ParameterizedTest(name = "Non dict-encoded string columns with vector size
{0}")
- @MethodSource("data")
+ @MethodSource("vectorSizes")
public void testNonDictStringColumns(int vectorSize)
{
- IncrementalIndex incrementalIndex = closer.register(new
OnheapIncrementalIndex.Builder()
- .setMaxRowCount(100)
- .setIndexSchema(
- IncrementalIndexSchema.builder()
- .withDimensionsSpec(
- DimensionsSpec.builder()
- .useSchemaDiscovery(false)
-
.setIncludeAllDimensions(true)
- .build()
- )
- .withVirtualColumns(
- VirtualColumns.create(
- new ExpressionVirtualColumn(
- "v0",
- "concat(\"A\", \"B\")",
- ColumnType.STRING,
- TestExprMacroTable.INSTANCE)
+ IncrementalIndex incrementalIndex = closer.register(
+ new OnheapIncrementalIndex.Builder()
+ .setMaxRowCount(100)
+ .setIndexSchema(
+ IncrementalIndexSchema.builder()
+ .withDimensionsSpec(
+ DimensionsSpec.builder()
+
.useSchemaDiscovery(false)
+
.setIncludeAllDimensions(true)
+ .build()
+ )
+ .withVirtualColumns(
+ VirtualColumns.create(
+ new ExpressionVirtualColumn(
+ "v0",
+ "concat(\"A\", \"B\")",
+ ColumnType.STRING,
+ TestExprMacroTable.INSTANCE
+ )
+ )
)
- )
- .withRollup(false)
- .build()
- )
- .build());
+ .withRollup(false)
+ .build()
+ )
+ .build()
+ );
final List<String> signature = List.of("A", "B");
@@ -283,26 +330,29 @@ public class ShimCursorTest
incrementalIndex.add(autoRow(signature, 6, "Cat"));
incrementalIndex.add(autoRow(signature, 7, "Drew"));
- final SimpleQueryableIndex index = closer.register((SimpleQueryableIndex)
TestIndex.persistAndMemoryMap(incrementalIndex));
+ final SimpleQueryableIndex index =
+ closer.register((SimpleQueryableIndex)
TestIndex.persistAndMemoryMap(incrementalIndex));
final QueryableIndexCursorFactory queryableIndexCursorFactory = new
QueryableIndexCursorFactory(index);
- CursorBuildSpec cursorBuildSpec = CursorBuildSpec.builder()
- .setQueryContext(
- QueryContext.of(
-
Map.of(QueryContexts.VECTOR_SIZE_KEY, vectorSize)
- )
- )
-
.setVirtualColumns(VirtualColumns.create(
-
new ExpressionVirtualColumn(
-
"v0",
-
"concat(\"A\", \"B\")",
-
ColumnType.STRING,
-
TestExprMacroTable.INSTANCE)
- )
- )
- .build();
+ CursorBuildSpec cursorBuildSpec =
+ CursorBuildSpec.builder()
+ .setQueryContext(
+ QueryContext.of(
+ Map.of(QueryContexts.VECTOR_SIZE_KEY,
vectorSize)
+ )
+ )
+ .setVirtualColumns(VirtualColumns.create(
+ new ExpressionVirtualColumn(
+ "v0",
+ "concat(\"A\", \"B\")",
+ ColumnType.STRING,
+ TestExprMacroTable.INSTANCE
+ )
+ )
+ )
+ .build();
CursorHolder cursorHolder =
closer.register(queryableIndexCursorFactory.makeCursorHolder(cursorBuildSpec));
- Assertions.assertTrue(cursorHolder.canVectorize());
+ assertTrue(cursorHolder.canVectorize());
VectorCursor vectorCursor = cursorHolder.asVectorCursor();
Cursor cursor = cursorHolder.asCursor();
@@ -311,6 +361,57 @@ public class ShimCursorTest
compareCursors(List.of("A", "B", "v0"), cursor, shimCursor);
}
+ @ParameterizedTest(name = "vectorSize = {0}")
+ @MethodSource("vectorSizes")
+ public void testArrayColumns(int vectorSize)
+ {
+ IncrementalIndex incrementalIndex = closer.register(
+ new OnheapIncrementalIndex.Builder()
+ .setMaxRowCount(100)
+ .setIndexSchema(
+ IncrementalIndexSchema
+ .builder()
+ .withDimensionsSpec(
+ DimensionsSpec.builder()
+ .useSchemaDiscovery(false)
+ .setIncludeAllDimensions(false)
+ .setDimensions(
+ List.of(
+ new
AutoTypeColumnSchema("longArr", ColumnType.LONG_ARRAY),
+ new
AutoTypeColumnSchema("doubleArr", ColumnType.DOUBLE_ARRAY),
+ new
AutoTypeColumnSchema("stringArr", ColumnType.STRING_ARRAY)
+ )
+ )
+ .build()
+ )
+ .withRollup(false)
+ .build()
+ )
+ .build());
+
+ final List<String> signature = List.of("longArr", "doubleArr",
"stringArr");
+
+ incrementalIndex.add(autoRow(signature, arr(2L, 3L), arr(2.2, 3.2),
arr("a", "b")));
+ incrementalIndex.add(autoRow(signature, null, null, null));
+ incrementalIndex.add(autoRow(signature, arr(4L), arr(4.2), arr("c")));
+
+ final SimpleQueryableIndex index =
+ closer.register((SimpleQueryableIndex)
TestIndex.persistAndMemoryMap(incrementalIndex));
+ final QueryableIndexCursorFactory queryableIndexCursorFactory = new
QueryableIndexCursorFactory(index);
+ final CursorBuildSpec cursorBuildSpec =
+ CursorBuildSpec.builder()
+
.setQueryContext(QueryContext.of(Map.of(QueryContexts.VECTOR_SIZE_KEY,
vectorSize)))
+ .build();
+ final CursorHolder cursorHolder =
closer.register(queryableIndexCursorFactory.makeCursorHolder(cursorBuildSpec));
+ assertTrue(cursorHolder.canVectorize());
+
+ final VectorCursor vectorCursor = cursorHolder.asVectorCursor();
+ final Cursor cursor = cursorHolder.asCursor();
+ final ShimCursor shimCursor = new ShimCursor(vectorCursor);
+
+ compareCursors(signature, cursor, shimCursor);
+ }
+
private static List<Object> arr(Object... vals)
{
return Arrays.asList(vals);
@@ -332,76 +433,217 @@ public class ShimCursorTest
/**
* Compares an expected {@link Cursor} to a {@link ShimCursor} and asserts
that they perform in a similar way.
*/
- private static void compareCursors(List<String> signature, Cursor expected,
ShimCursor actual)
+ private static void compareCursors(List<String> signature, Cursor
expectedCursor, ShimCursor actualCursor)
{
- final ColumnSelectorFactory expectedFactory =
expected.getColumnSelectorFactory();
- final ColumnSelectorFactory actualFactory =
actual.getColumnSelectorFactory();
- while (!expected.isDone()) {
- Assertions.assertFalse(actual.isDone());
+ final Map<String, ColumnCapabilities> capabilitiesMap = new HashMap<>();
+ final ColumnSelectorFactory expectedFactory =
expectedCursor.getColumnSelectorFactory();
+ final ColumnSelectorFactory actualFactory =
actualCursor.getColumnSelectorFactory();
+
+ for (String columnName : signature) {
+ // Check that capabilities match.
+ final ColumnCapabilities expectedCapabilities =
expectedFactory.getColumnCapabilities(columnName);
+ final ColumnCapabilities actualCapabilities =
actualFactory.getColumnCapabilities(columnName);
+ compareCapabilities(columnName, expectedCapabilities,
actualCapabilities);
+ capabilitiesMap.put(columnName, expectedCapabilities);
+ }
+
+ final Map<String, DimensionSelector> expectedDimensionSelectors = new
HashMap<>();
+ final Map<String, DimensionSelector> actualDimensionSelectors = new
HashMap<>();
+
+ final Map<String, ColumnValueSelector<?>> expectedValueSelectors = new
HashMap<>();
+ final Map<String, ColumnValueSelector<?>> actualValueSelectors = new
HashMap<>();
+
+ for (String columnName : signature) {
+ if (shouldTestDimensionSelector(capabilitiesMap.get(columnName))) {
+ expectedDimensionSelectors.put(
+ columnName,
+ expectedFactory.makeDimensionSelector(new
DefaultDimensionSpec(columnName, columnName))
+ );
+
+ actualDimensionSelectors.put(
+ columnName,
+ actualFactory.makeDimensionSelector(new
DefaultDimensionSpec(columnName, columnName))
+ );
+ }
+
+ expectedValueSelectors.put(columnName,
expectedFactory.makeColumnValueSelector(columnName));
+ actualValueSelectors.put(columnName,
actualFactory.makeColumnValueSelector(columnName));
+ }
+
+ while (!expectedCursor.isDone()) {
+ assertFalse(actualCursor.isDone());
+
for (String columnName : signature) {
- compareColumnValueSelector(columnName, expectedFactory, actualFactory);
- compareDimSelectorIfSupported(columnName, expectedFactory,
actualFactory);
+ final ColumnCapabilities capabilities =
capabilitiesMap.get(columnName);
+
+ compareColumnValueSelector(
+ columnName,
+ capabilities,
+ expectedValueSelectors.get(columnName),
+ actualValueSelectors.get(columnName)
+ );
+
+ if (shouldTestDimensionSelector(capabilities)) {
+ compareDimensionSelector(
+ columnName,
+ expectedDimensionSelectors.get(columnName),
+ actualDimensionSelectors.get(columnName)
+ );
+ }
}
- expected.advance();
- actual.advance();
+ expectedCursor.advance();
+ actualCursor.advance();
}
- Assertions.assertTrue(actual.isDone());
+ assertTrue(actualCursor.isDone());
}
- private static void compareColumnValueSelector(
+ private static boolean shouldTestDimensionSelector(final ColumnCapabilities
capabilities)
+ {
+ // makeDimensionSelector for array columns throws an exception on
creation, don't test it
+ return capabilities == null || !capabilities.is(ValueType.ARRAY);
+ }
+
+ private static void compareCapabilities(
String columnName,
- ColumnSelectorFactory expectedFactory,
- ColumnSelectorFactory actualFactory
+ @Nullable ColumnCapabilities expectedCapabilities,
+ @Nullable ColumnCapabilities actualCapabilities
)
{
- final ColumnCapabilities expectedCapabilities =
expectedFactory.getColumnCapabilities(columnName);
- final ColumnCapabilities actualCapabilities =
actualFactory.getColumnCapabilities(columnName);
-
- final ColumnValueSelector<?> expectedSelector =
expectedFactory.makeColumnValueSelector(columnName);
- final ColumnValueSelector<?> actualSelector =
actualFactory.makeColumnValueSelector(columnName);
+ assertEquals(
+ expectedCapabilities != null,
+ actualCapabilities != null,
+ "presence of capabilities for " + columnName
+ );
if (expectedCapabilities == null) {
- Assertions.assertNull(actualCapabilities);
- Assertions.assertTrue(actualSelector.isNull());
return;
}
- if (expectedCapabilities.isNumeric()) {
- Assertions.assertTrue(actualCapabilities.isNumeric());
- Assertions.assertEquals(expectedSelector.getDouble(),
actualSelector.getDouble());
- Assertions.assertEquals(expectedSelector.getLong(),
actualSelector.getLong());
- Assertions.assertEquals(expectedSelector.getFloat(),
actualSelector.getFloat());
- } else if (expectedCapabilities.isArray()) {
- Assertions.assertTrue(actualCapabilities.isArray());
- Assertions.assertArrayEquals((Object[]) expectedSelector.getObject(),
(Object[]) actualSelector.getObject());
+ assertEquals(
+ expectedCapabilities.getType(),
+ actualCapabilities.getType(),
+ "type of " + columnName
+ );
+
+ assertEquals(
+ expectedCapabilities.getElementType(),
+ actualCapabilities.getElementType(),
+ "elementType of " + columnName
+ );
+
+ assertEquals(
+ expectedCapabilities.getComplexTypeName(),
+ actualCapabilities.getComplexTypeName(),
+ "complexTypeName of " + columnName
+ );
+
+ assertEquals(
+ expectedCapabilities.isDictionaryEncoded(),
+ actualCapabilities.isDictionaryEncoded(),
+ "dictionaryEncoded of " + columnName
+ );
+
+ assertEquals(
+ expectedCapabilities.areDictionaryValuesUnique(),
+ actualCapabilities.areDictionaryValuesUnique(),
+ "areDictionaryValuesUnique of " + columnName
+ );
+
+ assertEquals(
+ expectedCapabilities.areDictionaryValuesSorted(),
+ actualCapabilities.areDictionaryValuesSorted(),
+ "areDictionaryValuesSorted of " + columnName
+ );
+
+ assertEquals(
+ expectedCapabilities.hasNulls(),
+ actualCapabilities.hasNulls(),
+ "hasNulls of " + columnName
+ );
+
+ assertEquals(
+ expectedCapabilities.hasMultipleValues(),
+ actualCapabilities.hasMultipleValues(),
+ "hasMultipleValues of " + columnName
+ );
+ }
+
+ /**
+ * Verify that the "actualFactory" capabilities and current value match
+ */
+ private static void compareColumnValueSelector(
+ String columnName,
+ ColumnCapabilities capabilities,
+ ColumnValueSelector<?> expectedSelector,
+ ColumnValueSelector<?> actualSelector
+ )
+ {
+ if (capabilities != null && capabilities.isNumeric()) {
+ assertEquals(expectedSelector.getLong(), actualSelector.getLong(),
"getLong for " + columnName);
+ assertEquals(expectedSelector.getDouble(), actualSelector.getDouble(),
"getDouble for " + columnName);
+ assertEquals(expectedSelector.getFloat(), actualSelector.getFloat(),
"getFloat for " + columnName);
+ assertEquals(expectedSelector.isNull(), actualSelector.isNull(), "isNull
for " + columnName);
+ }
+
+ final Object expectedObject = expectedSelector.getObject();
+ final Object actualObject = actualSelector.getObject();
+
+ if (expectedObject instanceof Object[]) {
+ assertThat("type of getObject for " + columnName, actualObject,
CoreMatchers.instanceOf(Object[].class));
+ assertArrayEquals((Object[]) expectedObject, (Object[]) actualObject,
"getObject for " + columnName);
} else {
- Assertions.assertEquals(expectedSelector.getObject(),
actualSelector.getObject());
+ assertEquals(expectedObject, actualObject, "getObject for " +
columnName);
}
}
- private static void compareDimSelectorIfSupported(
+ private static void compareDimensionSelector(
String columnName,
- ColumnSelectorFactory expectedFactory,
- ColumnSelectorFactory actualFactory
+ DimensionSelector expectedSelector,
+ DimensionSelector actualSelector
)
{
- final ColumnCapabilities expectedCapabilities =
expectedFactory.getColumnCapabilities(columnName);
-
- if (expectedCapabilities != null &&
expectedCapabilities.toColumnType().equals(ColumnType.STRING)) {
- final DimensionSelector expectedDimSelector =
expectedFactory.makeDimensionSelector(DefaultDimensionSpec.of(
- columnName));
- final DimensionSelector actualDimSelector =
actualFactory.makeDimensionSelector(DefaultDimensionSpec.of(
- columnName));
-
- Assertions.assertEquals(expectedDimSelector.getObject(),
actualDimSelector.getObject());
- IndexedInts expectedInts = expectedDimSelector.getRow();
- IndexedInts actualInts = actualDimSelector.getRow();
- int numValues = expectedInts.size();
- Assertions.assertEquals(numValues, actualInts.size());
- for (int i = 0; i < numValues; i++) {
- Assertions.assertEquals(expectedInts.get(i), actualInts.get(i));
+ assertEquals(
+ expectedSelector.nameLookupPossibleInAdvance(),
+ actualSelector.nameLookupPossibleInAdvance(),
+ "nameLookupPossibleInAdvance for " + columnName
+ );
+ assertEquals(
+ expectedSelector.supportsLookupNameUtf8(),
+ actualSelector.supportsLookupNameUtf8(),
+ "supportsLookupNameUtf8 for " + columnName
+ );
+ assertEquals(
+ expectedSelector.idLookup() != null,
+ actualSelector.idLookup() != null,
+ "presence of idLookup for " + columnName
+ );
+
+ // getObject checks
+ assertEquals(expectedSelector.getObject(), actualSelector.getObject(),
"getObject for " + columnName);
+
+ // getRow and lookupName/lookupNameUtf8 checks
+ final IntList expectedRow = new IntArrayList();
+ final IntList actualRow = new IntArrayList();
+ expectedSelector.getRow().forEach(expectedRow::add);
+ actualSelector.getRow().forEach(actualRow::add);
+
+ assertEquals(expectedRow, actualRow, "getRow for " + columnName);
+
+ for (int i = 0; i < expectedRow.size(); i++) {
+ assertEquals(
+ expectedSelector.lookupName(expectedRow.getInt(i)),
+ actualSelector.lookupName(actualRow.getInt(i)),
+ "lookupName for " + columnName + " id#" + expectedRow.getInt(i)
+ );
+
+ if (expectedSelector.supportsLookupNameUtf8()) {
+ assertEquals(
+
StringUtils.fromUtf8Nullable(expectedSelector.lookupNameUtf8(expectedRow.getInt(i))),
+
StringUtils.fromUtf8Nullable(actualSelector.lookupNameUtf8(actualRow.getInt(i))),
+ "lookupNameUtf8 for " + columnName + " id#" + expectedRow.getInt(i)
+ );
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]