This is an automated email from the ASF dual-hosted git repository.
cwylie 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 fd771c06c0e fixes for projection matching logic and unnest/join cursor
build spec translation (#18451)
fd771c06c0e is described below
commit fd771c06c0e523af27d7c747c4c921a047b96f85
Author: Clint Wylie <[email protected]>
AuthorDate: Wed Sep 3 17:28:35 2025 -0700
fixes for projection matching logic and unnest/join cursor build spec
translation (#18451)
---
.../org/apache/druid/segment/CursorBuildSpec.java | 21 ++-
.../segment/UnnestColumnValueSelectorCursor.java | 5 +-
.../apache/druid/segment/UnnestCursorFactory.java | 159 ++++++++++++-----
.../druid/segment/UnnestDimensionCursor.java | 7 +-
.../segment/join/HashJoinSegmentCursorFactory.java | 31 +++-
.../projections/ProjectionMatchBuilder.java | 20 ---
.../druid/segment/projections/Projections.java | 67 ++-----
.../apache/druid/segment/IndexMergerTestBase.java | 3 +
.../UnnestColumnValueSelectorCursorTest.java | 60 +++----
.../druid/segment/UnnestCursorFactoryTest.java | 197 ++++++++++++++++++++-
.../druid/segment/projections/ProjectionsTest.java | 5 +
11 files changed, 386 insertions(+), 189 deletions(-)
diff --git
a/processing/src/main/java/org/apache/druid/segment/CursorBuildSpec.java
b/processing/src/main/java/org/apache/druid/segment/CursorBuildSpec.java
index 35e847818e3..001805ca288 100644
--- a/processing/src/main/java/org/apache/druid/segment/CursorBuildSpec.java
+++ b/processing/src/main/java/org/apache/druid/segment/CursorBuildSpec.java
@@ -117,7 +117,7 @@ public class CursorBuildSpec
/**
* {@link Filter} to supply to the {@link CursorHolder}. Only rows which
match will be available through the
- * selectors created from the {@link Cursor} or {@link
org.apache.druid.segment.vector.VectorCursor}
+ * selectors created from the {@link Cursor} or {@link VectorCursor}
*/
@Nullable
public Filter getFilter()
@@ -128,7 +128,7 @@ public class CursorBuildSpec
/**
* {@link Interval} filter to supply to the {@link CursorHolder}. Only rows
whose timestamps fall within this range
* will be available through the selectors created from the {@link Cursor} or
- * {@link org.apache.druid.segment.vector.VectorCursor}
+ * {@link VectorCursor}
*/
public Interval getInterval()
{
@@ -136,8 +136,8 @@ public class CursorBuildSpec
}
/**
- * Set of physical columns required from a cursor. If null, and {@link
#groupingColumns} is null or empty and
- * {@link #aggregators} is null or empty, then a {@link CursorHolder} must
assume that ALL columns are required.
+ * Set of physical columns required from a cursor. If null, then a {@link
CursorHolder} must assume that ALL columns
+ * are required.
*/
@Nullable
public Set<String> getPhysicalColumns()
@@ -156,7 +156,7 @@ public class CursorBuildSpec
/**
* Any columns which will be used for grouping by a query engine for the
{@link CursorHolder}, useful for
- * specializing the {@link Cursor} or {@link
org.apache.druid.segment.vector.VectorCursor} if any pre-aggregated
+ * specializing the {@link Cursor} or {@link VectorCursor} if any
pre-aggregated
* data is available.
*/
@Nullable
@@ -168,7 +168,7 @@ public class CursorBuildSpec
/**
* Any {@link AggregatorFactory} which will be used by a query engine for
the {@link CursorHolder}, useful
* to assist in determining if {@link CursorHolder#canVectorize()}, as well
as specializing the {@link Cursor} or
- * {@link org.apache.druid.segment.vector.VectorCursor} if any
pre-aggregated data is available.
+ * {@link VectorCursor} if any pre-aggregated data is available.
*/
@Nullable
public List<AggregatorFactory> getAggregators()
@@ -179,7 +179,7 @@ public class CursorBuildSpec
/**
* List of all {@link OrderBy} columns which a query engine will use to sort
its results to supply to the
* {@link CursorHolder}, which can allow optimization of the provided {@link
Cursor} or
- * {@link org.apache.druid.segment.vector.VectorCursor} if data matching the
preferred ordering is available.
+ * {@link VectorCursor} if data matching the preferred ordering is available.
* <p>
* If not specified, the cursor will advance in the native order of the
underlying data.
*/
@@ -190,7 +190,7 @@ public class CursorBuildSpec
/**
* {@link QueryContext} for the {@link CursorHolder} to provide a mechanism
to push various data into
- * {@link Cursor} and {@link org.apache.druid.segment.vector.VectorCursor}
such as
+ * {@link Cursor} and {@link VectorCursor} such as
* {@link org.apache.druid.query.QueryContexts#VECTORIZE_KEY} and
* {@link org.apache.druid.query.QueryContexts#VECTOR_SIZE_KEY}
*/
@@ -201,7 +201,7 @@ public class CursorBuildSpec
/**
* {@link QueryMetrics} to use for measuring things involved with {@link
Cursor} and
- * {@link org.apache.druid.segment.vector.VectorCursor} creation.
+ * {@link VectorCursor} creation.
*/
@Nullable
public QueryMetrics<?> getQueryMetrics()
@@ -381,8 +381,7 @@ public class CursorBuildSpec
* @see CursorBuildSpec#getPhysicalColumns() for usage. The backing value
is not automatically populated by calls to
* {@link #setFilter(Filter)}, {@link #setVirtualColumns(VirtualColumns)},
{@link #setAggregators(List)}, or
* {@link #setPreferredOrdering(List)}, so this must be explicitly set for
all required physical columns. If set to
- * null, and {@link #groupingColumns} is null or empty and {@link
#aggregators} is null or empty, then a
- * {@link CursorHolder} must assume that ALL columns are required
+ * null, then a {@link CursorHolder} must assume that ALL columns are
required
*/
public CursorBuildSpecBuilder setPhysicalColumns(@Nullable Set<String>
physicalColumns)
{
diff --git
a/processing/src/main/java/org/apache/druid/segment/UnnestColumnValueSelectorCursor.java
b/processing/src/main/java/org/apache/druid/segment/UnnestColumnValueSelectorCursor.java
index 57aa5683c8d..260899df4d5 100644
---
a/processing/src/main/java/org/apache/druid/segment/UnnestColumnValueSelectorCursor.java
+++
b/processing/src/main/java/org/apache/druid/segment/UnnestColumnValueSelectorCursor.java
@@ -70,8 +70,7 @@ public class UnnestColumnValueSelectorCursor implements Cursor
public UnnestColumnValueSelectorCursor(
Cursor cursor,
ColumnSelectorFactory baseColumnSelectorFactory,
- VirtualColumn unnestColumn,
- String outputColumnName
+ VirtualColumn unnestColumn
)
{
this.baseCursor = cursor;
@@ -81,8 +80,8 @@ public class UnnestColumnValueSelectorCursor implements Cursor
this.baseColumnSelectorFactory
);
this.unnestColumn = unnestColumn;
+ this.outputName = unnestColumn.getOutputName();
this.index = 0;
- this.outputName = outputColumnName;
this.needInitialization = true;
}
diff --git
a/processing/src/main/java/org/apache/druid/segment/UnnestCursorFactory.java
b/processing/src/main/java/org/apache/druid/segment/UnnestCursorFactory.java
index e316022421b..177f2c02416 100644
--- a/processing/src/main/java/org/apache/druid/segment/UnnestCursorFactory.java
+++ b/processing/src/main/java/org/apache/druid/segment/UnnestCursorFactory.java
@@ -22,8 +22,8 @@ package org.apache.druid.segment;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
-import org.apache.druid.java.util.common.Pair;
import org.apache.druid.java.util.common.io.Closer;
+import org.apache.druid.query.Order;
import org.apache.druid.query.OrderBy;
import org.apache.druid.query.filter.BooleanFilter;
import org.apache.druid.query.filter.DimFilter;
@@ -51,7 +51,6 @@ import org.apache.druid.utils.CloseableUtils;
import javax.annotation.Nullable;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -79,43 +78,19 @@ public class UnnestCursorFactory implements CursorFactory
public CursorHolder makeCursorHolder(CursorBuildSpec spec)
{
final String input = getUnnestInputIfDirectAccess(unnestColumn);
- final Pair<Filter, Filter> filterPair = computeBaseAndPostUnnestFilters(
+ final UnnestFilterSplit filterSplit = computeBaseAndPostUnnestFilters(
spec.getFilter(),
filter != null ? filter.toFilter() : null,
spec.getVirtualColumns(),
+ unnestColumn,
input,
- input == null ? null : spec.getVirtualColumns()
-
.getColumnCapabilitiesWithFallback(baseCursorFactory, input)
+ input == null ? null :
spec.getVirtualColumns().getColumnCapabilitiesWithFallback(baseCursorFactory,
input)
+ );
+ final CursorBuildSpec unnestBuildSpec = transformCursorBuildSpec(
+ spec,
+ unnestColumn,
+ filterSplit.getBaseTableFilter()
);
- final Set<String> physicalColumns;
- if (spec.getPhysicalColumns() == null) {
- physicalColumns = null;
- } else {
- physicalColumns = new HashSet<>();
- for (String column : unnestColumn.requiredColumns()) {
- if (!spec.getVirtualColumns().exists(column)) {
- physicalColumns.add(column);
- }
- }
- if (filter != null) {
- for (String column : filter.getRequiredColumns()) {
- if (!spec.getVirtualColumns().exists(column)) {
- physicalColumns.add(column);
- }
- }
- }
- for (String column : spec.getPhysicalColumns()) {
- if (!column.equals(unnestColumn.getOutputName())) {
- physicalColumns.add(column);
- }
- }
- }
- final CursorBuildSpec unnestBuildSpec =
- CursorBuildSpec.builder(spec)
- .setFilter(filterPair.lhs)
- .setPhysicalColumns(physicalColumns)
-
.setVirtualColumns(VirtualColumns.create(Collections.singletonList(unnestColumn)))
- .build();
return new CursorHolder()
{
@@ -141,21 +116,19 @@ public class UnnestCursorFactory implements CursorFactory
unnestCursor = new UnnestDimensionCursor(
cursor,
cursor.getColumnSelectorFactory(),
- unnestColumn,
- unnestColumn.getOutputName()
+ unnestColumn
);
} else {
unnestCursor = new UnnestColumnValueSelectorCursor(
cursor,
cursor.getColumnSelectorFactory(),
- unnestColumn,
- unnestColumn.getOutputName()
+ unnestColumn
);
}
return PostJoinCursor.wrap(
unnestCursor,
spec.getVirtualColumns(),
- filterPair.rhs
+ filterSplit.getPostUnnestFilter()
);
}
@@ -235,10 +208,11 @@ public class UnnestCursorFactory implements CursorFactory
* @return pair of pre- and post-unnest filters
*/
@VisibleForTesting
- public Pair<Filter, Filter> computeBaseAndPostUnnestFilters(
+ static UnnestFilterSplit computeBaseAndPostUnnestFilters(
@Nullable final Filter queryFilter,
@Nullable final Filter unnestFilter,
final VirtualColumns queryVirtualColumns,
+ final VirtualColumn unnestColumn,
@Nullable final String inputColumn,
@Nullable final ColumnCapabilities inputColumnCapabilites
)
@@ -290,6 +264,7 @@ public class UnnestCursorFactory implements CursorFactory
if (queryFilter instanceof BooleanFilter) {
List<Filter> preFilterList = recursiveRewriteOnUnnestFilters(
(BooleanFilter) queryFilter,
+ unnestColumn,
inputColumn,
inputColumnCapabilites,
filterSplitter
@@ -316,7 +291,7 @@ public class UnnestCursorFactory implements CursorFactory
}
filterSplitter.addPostFilterWithPreFilterIfRewritePossible(unnestFilter,
false);
- return Pair.of(
+ return new UnnestFilterSplit(
Filters.maybeAnd(filterSplitter.filtersPushedDownToBaseCursor).orElse(null),
Filters.maybeAnd(filterSplitter.filtersForPostUnnestCursor).orElse(null)
);
@@ -343,8 +318,9 @@ public class UnnestCursorFactory implements CursorFactory
* @param inputColumn input column to unnest if it's a direct
access; otherwise null
* @param inputColumnCapabilites input column capabilities if known;
otherwise null
*/
- private List<Filter> recursiveRewriteOnUnnestFilters(
+ private static List<Filter> recursiveRewriteOnUnnestFilters(
BooleanFilter queryFilter,
+ VirtualColumn unnestColumn,
final String inputColumn,
final ColumnCapabilities inputColumnCapabilites,
final FilterSplitter filterSplitter
@@ -356,6 +332,7 @@ public class UnnestCursorFactory implements CursorFactory
if (filter instanceof AndFilter) {
List<Filter> andChildFilters = recursiveRewriteOnUnnestFilters(
(BooleanFilter) filter,
+ unnestColumn,
inputColumn,
inputColumnCapabilites,
filterSplitter
@@ -366,6 +343,7 @@ public class UnnestCursorFactory implements CursorFactory
} else if (filter instanceof OrFilter) {
List<Filter> orChildFilters = recursiveRewriteOnUnnestFilters(
(BooleanFilter) filter,
+ unnestColumn,
inputColumn,
inputColumnCapabilites,
filterSplitter
@@ -449,7 +427,7 @@ public class UnnestCursorFactory implements CursorFactory
* Computes the capabilities of {@link #unnestColumn}, after unnesting.
*/
@Nullable
- public static ColumnCapabilities computeOutputColumnCapabilities(
+ static ColumnCapabilities computeOutputColumnCapabilities(
final ColumnInspector baseColumnInspector,
final VirtualColumn unnestColumn
)
@@ -475,6 +453,74 @@ public class UnnestCursorFactory implements CursorFactory
}
}
+ /**
+ * Converts a {@link CursorBuildSpec} to the base table {@link
CursorBuildSpec}, ensuring that all required columns
+ * of the original spec are added to {@link
CursorBuildSpec#getPhysicalColumns()} and the unnest column is added to
+ * {@link CursorBuildSpec#getVirtualColumns()}
+ */
+ @VisibleForTesting
+ static CursorBuildSpec transformCursorBuildSpec(
+ CursorBuildSpec spec,
+ VirtualColumn unnestColumn,
+ @Nullable Filter baseTableFilter
+ )
+ {
+ final Set<String> physicalColumns;
+ if (spec.getPhysicalColumns() == null) {
+ physicalColumns = null;
+ } else {
+ physicalColumns = new HashSet<>();
+
+ // add all physical columns, skip unnest column if specified as a
physical column, we'll deal with it next
+ for (String column : spec.getPhysicalColumns()) {
+ if (!column.equals(unnestColumn.getOutputName())) {
+ physicalColumns.add(column);
+ }
+ }
+
+ // add all unnest input physical columns
+ for (String input : unnestColumn.requiredColumns()) {
+ if (!spec.getVirtualColumns().exists(input)) {
+ physicalColumns.add(input);
+ }
+ }
+
+ // add all the base table filter columns. this is probably unecessary -
while part of the filter might have been
+ // on the unnest rather than the query and so its required columns
missing from the physical column list, it is
+ // likely the unnest filter is only referencing the unnest column, which
is already covered by the physical
+ // column substitution... however just in case something wild happened
on the spec we add all these too
+ if (baseTableFilter != null) {
+ for (String column : baseTableFilter.getRequiredColumns()) {
+ if (!spec.getVirtualColumns().exists(column)) {
+ physicalColumns.add(column);
+ }
+ }
+ }
+ }
+
+ // trim off the grouping, aggregators, and ordering (other than time) to
turn this into a plain scan cursor build
+ // spec this could be improved in the future to be able to match
projections. in some cases, we could push this
+ // through as a grouping, but would need to push in all the query virtual
columns, and ensure that aggregators do
+ // not refer to the unnest column (the filter has already been
preprocessed and passed in as a separate argument to
+ // this method)
+ Order timeOrder = Cursors.getTimeOrdering(spec.getPreferredOrdering());
+ List<OrderBy> maybeOrderByTime = List.of();
+ if (timeOrder == Order.DESCENDING) {
+ maybeOrderByTime = Cursors.descendingTimeOrder();
+ } else if (timeOrder == Order.ASCENDING) {
+ maybeOrderByTime = Cursors.ascendingTimeOrder();
+ }
+ return CursorBuildSpec.builder()
+ .setInterval(spec.getInterval())
+ .setFilter(baseTableFilter)
+ .setPhysicalColumns(physicalColumns)
+
.setVirtualColumns(VirtualColumns.create(List.of(unnestColumn)))
+ .setPreferredOrdering(maybeOrderByTime)
+ .setQueryContext(spec.getQueryContext())
+ .setQueryMetrics(spec.getQueryMetrics())
+ .build();
+ }
+
/**
* Requirement for {@link #rewriteFilterOnUnnestColumnIfPossible}: filter
must support rewrites and also must map
* over multi-value strings. (Rather than treat them as arrays.) There isn't
a method on the Filter interface that
@@ -618,4 +664,31 @@ public class UnnestCursorFactory implements CursorFactory
return preFilterCount;
}
}
+
+ @VisibleForTesting
+ static final class UnnestFilterSplit
+ {
+ @Nullable
+ private final Filter baseTableFilter;
+ @Nullable
+ private final Filter postUnnestFilter;
+
+ private UnnestFilterSplit(@Nullable Filter baseTableFilter, @Nullable
Filter postUnnestFilter)
+ {
+ this.baseTableFilter = baseTableFilter;
+ this.postUnnestFilter = postUnnestFilter;
+ }
+
+ @Nullable
+ public Filter getBaseTableFilter()
+ {
+ return baseTableFilter;
+ }
+
+ @Nullable
+ public Filter getPostUnnestFilter()
+ {
+ return postUnnestFilter;
+ }
+ }
}
diff --git
a/processing/src/main/java/org/apache/druid/segment/UnnestDimensionCursor.java
b/processing/src/main/java/org/apache/druid/segment/UnnestDimensionCursor.java
index 3012d31ff2a..cfd0e30e21d 100644
---
a/processing/src/main/java/org/apache/druid/segment/UnnestDimensionCursor.java
+++
b/processing/src/main/java/org/apache/druid/segment/UnnestDimensionCursor.java
@@ -81,8 +81,7 @@ public class UnnestDimensionCursor implements Cursor
public UnnestDimensionCursor(
Cursor cursor,
ColumnSelectorFactory baseColumnSelectorFactory,
- VirtualColumn unnestColumn,
- String outputColumnName
+ VirtualColumn unnestColumn
)
{
this.baseCursor = cursor;
@@ -91,9 +90,9 @@ public class UnnestDimensionCursor implements Cursor
DefaultDimensionSpec.of(unnestColumn.getOutputName()),
this.baseColumnSelectorFactory
);
- this.unnestColumn = unnestColumn;
this.index = 0;
- this.outputName = outputColumnName;
+ this.unnestColumn = unnestColumn;
+ this.outputName = unnestColumn.getOutputName();
this.needInitialization = true;
// this shouldn't happen, but just in case...
final IdLookup lookup = Preconditions.checkNotNull(dimSelector.idLookup());
diff --git
a/processing/src/main/java/org/apache/druid/segment/join/HashJoinSegmentCursorFactory.java
b/processing/src/main/java/org/apache/druid/segment/join/HashJoinSegmentCursorFactory.java
index b608017d9a7..b5354de02ad 100644
---
a/processing/src/main/java/org/apache/druid/segment/join/HashJoinSegmentCursorFactory.java
+++
b/processing/src/main/java/org/apache/druid/segment/join/HashJoinSegmentCursorFactory.java
@@ -24,12 +24,14 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.druid.java.util.common.io.Closer;
+import org.apache.druid.query.Order;
import org.apache.druid.query.OrderBy;
import org.apache.druid.query.filter.Filter;
import org.apache.druid.segment.Cursor;
import org.apache.druid.segment.CursorBuildSpec;
import org.apache.druid.segment.CursorFactory;
import org.apache.druid.segment.CursorHolder;
+import org.apache.druid.segment.Cursors;
import org.apache.druid.segment.VirtualColumn;
import org.apache.druid.segment.VirtualColumns;
import org.apache.druid.segment.column.ColumnCapabilities;
@@ -74,10 +76,6 @@ public class HashJoinSegmentCursorFactory implements
CursorFactory
@Override
public CursorHolder makeCursorHolder(CursorBuildSpec spec)
{
- // make a copy of CursorBuildSpec with filters removed
- final CursorBuildSpec.CursorBuildSpecBuilder cursorBuildSpecBuilder =
CursorBuildSpec.builder(spec)
-
.setFilter(null);
-
final Filter combinedFilter = baseFilterAnd(spec.getFilter());
// for physical column tracking, we start by copying base spec physical
columns
@@ -95,12 +93,15 @@ public class HashJoinSegmentCursorFactory implements
CursorFactory
if (clauses.isEmpty()) {
// if there are no clauses, we can just use the base cursor directly if
we apply the combined filter
- final CursorBuildSpec newSpec =
cursorBuildSpecBuilder.setFilter(combinedFilter)
-
.setPhysicalColumns(physicalColumns)
- .build();
+ final CursorBuildSpec newSpec = CursorBuildSpec.builder(spec)
+ .setFilter(combinedFilter)
+
.setPhysicalColumns(physicalColumns)
+ .build();
return baseCursorFactory.makeCursorHolder(newSpec);
}
+ // else we need to wipe out the grouping, aggregations, and ordering
+
return new CursorHolder()
{
final Closer joinablesCloser = Closer.create();
@@ -152,6 +153,22 @@ public class HashJoinSegmentCursorFactory implements
CursorFactory
baseFilter
);
+ // start with a full scan clipped to interval
+ final CursorBuildSpec.CursorBuildSpecBuilder cursorBuildSpecBuilder =
+ CursorBuildSpec.builder()
+ .setInterval(spec.getInterval())
+ .setQueryContext(spec.getQueryContext())
+ .setQueryMetrics(spec.getQueryMetrics());
+
+ // retain time ordering if preferred
+ Order timeOrder = Cursors.getTimeOrdering(spec.getPreferredOrdering());
+ if (timeOrder == Order.DESCENDING) {
+
cursorBuildSpecBuilder.setPreferredOrdering(Cursors.descendingTimeOrder());
+ } else if (timeOrder == Order.ASCENDING) {
+
cursorBuildSpecBuilder.setPreferredOrdering(Cursors.ascendingTimeOrder());
+ }
+
+ // add pushdown filters if present
if (joinFilterSplit.getBaseTableFilter().isPresent()) {
cursorBuildSpecBuilder.setFilter(joinFilterSplit.getBaseTableFilter().get());
}
diff --git
a/processing/src/main/java/org/apache/druid/segment/projections/ProjectionMatchBuilder.java
b/processing/src/main/java/org/apache/druid/segment/projections/ProjectionMatchBuilder.java
index 8a704120ae5..3709a9fec5d 100644
---
a/processing/src/main/java/org/apache/druid/segment/projections/ProjectionMatchBuilder.java
+++
b/processing/src/main/java/org/apache/druid/segment/projections/ProjectionMatchBuilder.java
@@ -27,7 +27,6 @@ import org.apache.druid.segment.VirtualColumns;
import javax.annotation.Nullable;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -45,7 +44,6 @@ public final class ProjectionMatchBuilder
private final Set<VirtualColumn> referencedVirtualColumns;
private final Map<String, String> remapColumns;
private final List<AggregatorFactory> combiningFactories;
- private final Set<String> matchedQueryColumns;
@Nullable
private Filter rewriteFilter;
@@ -55,7 +53,6 @@ public final class ProjectionMatchBuilder
this.referencedVirtualColumns = new HashSet<>();
this.remapColumns = new HashMap<>();
this.combiningFactories = new ArrayList<>();
- this.matchedQueryColumns = new HashSet<>();
}
/**
@@ -103,18 +100,6 @@ public final class ProjectionMatchBuilder
return this;
}
- public ProjectionMatchBuilder addMatchedQueryColumn(String queryColumn)
- {
- matchedQueryColumns.add(queryColumn);
- return this;
- }
-
- public ProjectionMatchBuilder addMatchedQueryColumns(Collection<String>
queryColumns)
- {
- matchedQueryColumns.addAll(queryColumns);
- return this;
- }
-
public ProjectionMatchBuilder rewriteFilter(Filter rewriteFilter)
{
this.rewriteFilter = rewriteFilter;
@@ -131,11 +116,6 @@ public final class ProjectionMatchBuilder
return remapColumns;
}
- public Set<String> getMatchedQueryColumns()
- {
- return matchedQueryColumns;
- }
-
public ProjectionMatch build(CursorBuildSpec queryCursorBuildSpec)
{
return new ProjectionMatch(
diff --git
a/processing/src/main/java/org/apache/druid/segment/projections/Projections.java
b/processing/src/main/java/org/apache/druid/segment/projections/Projections.java
index 7b280544abc..a91b17de58f 100644
---
a/processing/src/main/java/org/apache/druid/segment/projections/Projections.java
+++
b/processing/src/main/java/org/apache/druid/segment/projections/Projections.java
@@ -19,7 +19,6 @@
package org.apache.druid.segment.projections;
-import com.google.common.collect.Sets;
import org.apache.druid.data.input.impl.AggregateProjectionSpec;
import org.apache.druid.error.InvalidInput;
import org.apache.druid.java.util.common.granularity.Granularities;
@@ -115,6 +114,9 @@ public class Projections
if
(!queryCursorBuildSpec.isCompatibleOrdering(projection.getOrderingWithTimeColumnSubstitution()))
{
return null;
}
+ if
(CollectionUtils.isNullOrEmpty(queryCursorBuildSpec.getPhysicalColumns())) {
+ return null;
+ }
ProjectionMatchBuilder matchBuilder = new ProjectionMatchBuilder();
// match virtual columns first, which will populate the 'remapColumns' of
the match builder
@@ -123,23 +125,17 @@ public class Projections
return null;
}
-
- matchBuilder = matchGrouping(projection, queryCursorBuildSpec,
physicalColumnChecker, matchBuilder);
- if (matchBuilder == null) {
- return null;
- }
-
- matchBuilder = matchAggregators(projection, queryCursorBuildSpec,
matchBuilder);
+ matchBuilder = matchFilter(projection, queryCursorBuildSpec,
physicalColumnChecker, matchBuilder);
if (matchBuilder == null) {
return null;
}
- matchBuilder = matchFilter(projection, queryCursorBuildSpec,
physicalColumnChecker, matchBuilder);
+ matchBuilder = matchGrouping(projection, queryCursorBuildSpec,
physicalColumnChecker, matchBuilder);
if (matchBuilder == null) {
return null;
}
- matchBuilder = matchRemainingPhysicalColumns(projection,
queryCursorBuildSpec, physicalColumnChecker, matchBuilder);
+ matchBuilder = matchAggregators(projection, queryCursorBuildSpec,
matchBuilder);
if (matchBuilder == null) {
return null;
}
@@ -204,11 +200,9 @@ public class Projections
if (rewritten == ProjectionFilterMatch.INSTANCE) {
// we can remove the whole thing since the query filter exactly
matches the projection filter
matchBuilder.rewriteFilter(null);
- matchBuilder.addMatchedQueryColumns(originalRequired);
} else {
// otherwise, we partially rewrote the query filter to eliminate the
projection filter since it is baked in
matchBuilder.rewriteFilter(rewritten);
-
matchBuilder.addMatchedQueryColumns(Sets.difference(originalRequired,
rewritten.getRequiredColumns()));
}
} else {
// projection has a filter, but the query doesn't, no good
@@ -290,8 +284,7 @@ public class Projections
if (combining != null) {
matchBuilder.remapColumn(queryAgg.getName(), projectionAgg.getName())
.addReferencedPhysicalColumn(projectionAgg.getName())
- .addPreAggregatedAggregator(combining)
- .addMatchedQueryColumns(queryAgg.requiredFields());
+ .addPreAggregatedAggregator(combining);
foundMatch = true;
break;
}
@@ -304,39 +297,6 @@ public class Projections
return null;
}
- @Nullable
- public static ProjectionMatchBuilder matchRemainingPhysicalColumns(
- AggregateProjectionMetadata.Schema projection,
- CursorBuildSpec queryCursorBuildSpec,
- PhysicalColumnChecker physicalColumnChecker,
- ProjectionMatchBuilder matchBuilder
- )
- {
- // validate physical and virtual columns have all been accounted for
- final Set<String> matchedQueryColumns =
matchBuilder.getMatchedQueryColumns();
- if (queryCursorBuildSpec.getPhysicalColumns() != null) {
- for (String queryColumn : queryCursorBuildSpec.getPhysicalColumns()) {
- // a projection always has a __time column, it just might be a
constant of the segment interval start if the
- // projection itself did not transform the base table __time column
- if (ColumnHolder.TIME_COLUMN_NAME.equals(queryColumn)) {
- continue;
- }
- if (!matchedQueryColumns.contains(queryColumn)) {
- matchBuilder = matchQueryPhysicalColumn(
- queryColumn,
- projection,
- physicalColumnChecker,
- matchBuilder
- );
- if (matchBuilder == null) {
- return null;
- }
- }
- }
- }
- return matchBuilder;
- }
-
/**
* Ensure that the projection has the specified column required by a {@link
CursorBuildSpec} in one form or another.
* If the column is a {@link VirtualColumn} on the build spec, ensure that
the projection has an equivalent virtual
@@ -370,9 +330,6 @@ public class Projections
ProjectionMatchBuilder matchBuilder
)
{
- if (matchBuilder.getMatchedQueryColumns().contains(column)) {
- return matchBuilder;
- }
final VirtualColumn virtualColumn =
queryCursorBuildSpec.getVirtualColumns().getVirtualColumn(column);
if (virtualColumn != null) {
return matchQueryVirtualColumn(
@@ -408,13 +365,10 @@ public class Projections
if (!queryVirtualColumn.getOutputName().equals(remapColumnName)) {
matchBuilder.remapColumn(queryVirtualColumn.getOutputName(),
remapColumnName);
}
- return
matchBuilder.addMatchedQueryColumn(queryVirtualColumn.getOutputName())
-
.addMatchedQueryColumns(queryVirtualColumn.requiredColumns())
- .addReferencedPhysicalColumn(remapColumnName);
+ return matchBuilder.addReferencedPhysicalColumn(remapColumnName);
}
- matchBuilder.addMatchedQueryColumn(queryVirtualColumn.getOutputName())
- .addReferenceedVirtualColumn(queryVirtualColumn);
+ matchBuilder.addReferenceedVirtualColumn(queryVirtualColumn);
final List<String> requiredInputs = queryVirtualColumn.requiredColumns();
if (requiredInputs.size() == 1 &&
ColumnHolder.TIME_COLUMN_NAME.equals(requiredInputs.get(0))) {
// special handle time granularity. in the future this should be
reworked to push this concept into the
@@ -463,8 +417,7 @@ public class Projections
)
{
if (physicalColumnChecker.check(projection.getName(), column)) {
- return matchBuilder.addMatchedQueryColumn(column)
- .addReferencedPhysicalColumn(column);
+ return matchBuilder.addReferencedPhysicalColumn(column);
}
return null;
}
diff --git
a/processing/src/test/java/org/apache/druid/segment/IndexMergerTestBase.java
b/processing/src/test/java/org/apache/druid/segment/IndexMergerTestBase.java
index b6a1dfa0390..98eb6cb7906 100644
--- a/processing/src/test/java/org/apache/druid/segment/IndexMergerTestBase.java
+++ b/processing/src/test/java/org/apache/druid/segment/IndexMergerTestBase.java
@@ -94,6 +94,7 @@ import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
public abstract class IndexMergerTestBase extends InitializedNullHandlingTest
@@ -3071,6 +3072,7 @@ public abstract class IndexMergerTestBase extends
InitializedNullHandlingTest
ImmutableMap.of(QueryContexts.USE_PROJECTION, "a_hourly_c_sum")
)
)
+ .setPhysicalColumns(Set.of("c",
ColumnHolder.TIME_COLUMN_NAME))
.setVirtualColumns(
VirtualColumns.create(
Granularities.toVirtualColumn(Granularities.HOUR, "gran")
@@ -3089,6 +3091,7 @@ public abstract class IndexMergerTestBase extends
InitializedNullHandlingTest
ImmutableMap.of(QueryContexts.USE_PROJECTION, "a_c_sum")
)
)
+ .setPhysicalColumns(Set.of("a",
"c"))
.setAggregators(
Collections.singletonList(
new
LongSumAggregatorFactory("c", "c")
diff --git
a/processing/src/test/java/org/apache/druid/segment/UnnestColumnValueSelectorCursorTest.java
b/processing/src/test/java/org/apache/druid/segment/UnnestColumnValueSelectorCursorTest.java
index 5e60b1e0496..b87a7faf029 100644
---
a/processing/src/test/java/org/apache/druid/segment/UnnestColumnValueSelectorCursorTest.java
+++
b/processing/src/test/java/org/apache/druid/segment/UnnestColumnValueSelectorCursorTest.java
@@ -58,8 +58,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
unnestCursor.getColumnSelectorFactory()
.makeColumnValueSelector(OUTPUT_NAME);
@@ -91,8 +90,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
unnestCursor.getColumnSelectorFactory()
.makeColumnValueSelector(OUTPUT_NAME);
@@ -123,8 +121,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
unnestCursor.getColumnSelectorFactory()
.makeColumnValueSelector(OUTPUT_NAME);
@@ -157,8 +154,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "mv_to_array(\"dummy\")",
ColumnType.STRING, ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "mv_to_array(\"dummy\")",
ColumnType.STRING, ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
unnestCursor.getColumnSelectorFactory()
.makeColumnValueSelector(OUTPUT_NAME);
@@ -191,8 +187,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"",
ColumnType.STRING_ARRAY, ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"",
ColumnType.STRING_ARRAY, ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
unnestCursor.getColumnSelectorFactory()
.makeColumnValueSelector(OUTPUT_NAME);
@@ -230,8 +225,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
unnestCursor.getColumnSelectorFactory()
.makeColumnValueSelector(OUTPUT_NAME);
@@ -275,8 +269,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"",
ColumnType.STRING_ARRAY, ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"",
ColumnType.STRING_ARRAY, ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
unnestCursor.getColumnSelectorFactory()
.makeColumnValueSelector(OUTPUT_NAME);
@@ -308,8 +301,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
unnestCursor.getColumnSelectorFactory()
.makeColumnValueSelector(OUTPUT_NAME);
@@ -337,8 +329,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
unnestCursor.getColumnSelectorFactory()
.makeColumnValueSelector(OUTPUT_NAME);
@@ -371,8 +362,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"", null,
ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"", null,
ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
unnestCursor.getColumnSelectorFactory()
.makeColumnValueSelector(OUTPUT_NAME);
@@ -404,14 +394,12 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor childCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"", null,
ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"", null,
ExprMacroTable.nil())
);
UnnestColumnValueSelectorCursor parentCursor = new
UnnestColumnValueSelectorCursor(
childCursor,
childCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"" + OUTPUT_NAME + "\"",
null, ExprMacroTable.nil()),
- "tmp-out"
+ new ExpressionVirtualColumn("tmp-out", "\"" + OUTPUT_NAME + "\"",
null, ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
parentCursor.getColumnSelectorFactory()
.makeColumnValueSelector("tmp-out");
@@ -444,8 +432,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
unnestCursor.getColumnSelectorFactory()
.makeColumnValueSelector(OUTPUT_NAME);
@@ -481,8 +468,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
unnestCursor.getColumnSelectorFactory()
.makeColumnValueSelector(OUTPUT_NAME);
@@ -518,8 +504,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
unnestCursor.getColumnSelectorFactory()
.makeColumnValueSelector(OUTPUT_NAME);
@@ -551,8 +536,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
unnestCursor.getColumnSelectorFactory()
.makeColumnValueSelector(OUTPUT_NAME);
@@ -584,8 +568,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
unnestCursor.getColumnSelectorFactory()
.makeColumnValueSelector(OUTPUT_NAME);
@@ -620,8 +603,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"", null,
ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"", null,
ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
unnestCursor.getColumnSelectorFactory()
.makeColumnValueSelector(OUTPUT_NAME);
@@ -655,8 +637,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil())
);
// should return a column value selector for this case
BaseSingleValueDimensionSelector unnestDimSelector =
(BaseSingleValueDimensionSelector) unnestCursor.getColumnSelectorFactory()
@@ -697,8 +678,7 @@ public class UnnestColumnValueSelectorCursorTest extends
InitializedNullHandling
UnnestColumnValueSelectorCursor unnestCursor = new
UnnestColumnValueSelectorCursor(
listCursor,
listCursor.getColumnSelectorFactory(),
- new ExpressionVirtualColumn("__unnest__", "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil()),
- OUTPUT_NAME
+ new ExpressionVirtualColumn(OUTPUT_NAME, "\"dummy\"",
ColumnType.STRING, ExprMacroTable.nil())
);
ColumnValueSelector unnestColumnValueSelector =
unnestCursor.getColumnSelectorFactory()
.makeColumnValueSelector(OUTPUT_NAME);
diff --git
a/processing/src/test/java/org/apache/druid/segment/UnnestCursorFactoryTest.java
b/processing/src/test/java/org/apache/druid/segment/UnnestCursorFactoryTest.java
index ef26393a773..5d16e579bdd 100644
---
a/processing/src/test/java/org/apache/druid/segment/UnnestCursorFactoryTest.java
+++
b/processing/src/test/java/org/apache/druid/segment/UnnestCursorFactoryTest.java
@@ -22,7 +22,6 @@ package org.apache.druid.segment;
import com.google.common.collect.ImmutableList;
import org.apache.druid.data.input.InputSource;
import org.apache.druid.data.input.ResourceInputSource;
-import org.apache.druid.java.util.common.Pair;
import org.apache.druid.java.util.common.granularity.Granularities;
import org.apache.druid.java.util.common.guava.Sequences;
import org.apache.druid.java.util.common.io.Closer;
@@ -32,9 +31,11 @@ import org.apache.druid.query.dimension.DefaultDimensionSpec;
import org.apache.druid.query.filter.DimFilter;
import org.apache.druid.query.filter.EqualityFilter;
import org.apache.druid.query.filter.Filter;
+import org.apache.druid.query.filter.RangeFilter;
import org.apache.druid.query.filter.SelectorDimFilter;
import org.apache.druid.query.filter.ValueMatcher;
import org.apache.druid.segment.column.ColumnCapabilities;
+import org.apache.druid.segment.column.ColumnCapabilitiesImpl;
import org.apache.druid.segment.column.ColumnType;
import org.apache.druid.segment.column.RowSignature;
import org.apache.druid.segment.column.ValueType;
@@ -61,12 +62,14 @@ import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
import org.junit.rules.TemporaryFolder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Set;
import java.util.function.Function;
import java.util.function.ToLongFunction;
@@ -836,6 +839,190 @@ public class UnnestCursorFactoryTest extends
InitializedNullHandlingTest
}
}
+ @Test
+ public void testTransformCursor()
+ {
+ final String inputColumn = "col";
+ final String unnestColumn = "unnest";
+ ExpressionVirtualColumn identifier = new ExpressionVirtualColumn(
+ unnestColumn,
+ "\"" + inputColumn + "\"",
+ ColumnType.STRING_ARRAY,
+ ExprMacroTable.nil()
+ );
+ CursorBuildSpec buildSpec = CursorBuildSpec.builder()
+
.setPhysicalColumns(Set.of(unnestColumn))
+
.setGroupingColumns(List.of(unnestColumn))
+ .build();
+
+
+ CursorBuildSpec expected = CursorBuildSpec.builder()
+
.setPhysicalColumns(Set.of(inputColumn))
+
.setVirtualColumns(VirtualColumns.create(identifier))
+ .build();
+
+ CursorBuildSpec transformed = UnnestCursorFactory.transformCursorBuildSpec(
+ buildSpec,
+ identifier,
+ null
+ );
+
+ Assertions.assertEquals(expected, transformed);
+ }
+
+ @Test
+ public void testTransformCursorMoreGrouping()
+ {
+ final String unnestColumn = "unnest";
+ ExpressionVirtualColumn identifier = new ExpressionVirtualColumn(
+ unnestColumn,
+ "\"a\"",
+ ColumnType.STRING_ARRAY,
+ ExprMacroTable.nil()
+ );
+ CursorBuildSpec buildSpec = CursorBuildSpec.builder()
+
.setPhysicalColumns(Set.of(unnestColumn, "b", "c"))
+
.setGroupingColumns(List.of(unnestColumn, "b", "c"))
+ .build();
+
+
+ CursorBuildSpec expected = CursorBuildSpec.builder()
+ .setPhysicalColumns(Set.of("a",
"b", "c"))
+
.setVirtualColumns(VirtualColumns.create(identifier))
+ .build();
+
+ CursorBuildSpec transformed = UnnestCursorFactory.transformCursorBuildSpec(
+ buildSpec,
+ identifier,
+ null
+ );
+
+ Assertions.assertEquals(expected, transformed);
+ }
+
+ @Test
+ public void testTransformCursorFilter()
+ {
+ final String unnestColumn = "unnest";
+ ExpressionVirtualColumn identifier = new ExpressionVirtualColumn(
+ unnestColumn,
+ "\"a\"",
+ ColumnType.STRING_ARRAY,
+ ExprMacroTable.nil()
+ );
+ Filter unnestEquals = new EqualityFilter(unnestColumn, ColumnType.STRING,
"value", null);
+ Filter bRange = new RangeFilter("b", ColumnType.LONG, 1L, 10L, false,
false, null);
+ CursorBuildSpec buildSpec = CursorBuildSpec.builder()
+
.setPhysicalColumns(Set.of(unnestColumn, "b", "c"))
+
.setGroupingColumns(List.of(unnestColumn, "b", "c"))
+ .setFilter(bRange)
+ .build();
+
+ UnnestCursorFactory.UnnestFilterSplit split =
UnnestCursorFactory.computeBaseAndPostUnnestFilters(
+ buildSpec.getFilter(),
+ unnestEquals,
+ buildSpec.getVirtualColumns(),
+ identifier,
+ "a",
+ ColumnCapabilitiesImpl.createDefault().setType(ColumnType.STRING_ARRAY)
+ );
+
+ // expect unnest filter not pushed down since is array column
+ CursorBuildSpec expected = CursorBuildSpec.builder()
+ .setPhysicalColumns(Set.of("a",
"b", "c"))
+
.setVirtualColumns(VirtualColumns.create(identifier))
+ .setFilter(bRange)
+ .build();
+
+ CursorBuildSpec transformed = UnnestCursorFactory.transformCursorBuildSpec(
+ buildSpec,
+ identifier,
+ split.getBaseTableFilter()
+ );
+
+ Assertions.assertEquals(expected, transformed);
+ }
+
+ @Test
+ public void testTransformCursorFilterMvd()
+ {
+ final String unnestColumn = "unnest";
+ ExpressionVirtualColumn identifier = new ExpressionVirtualColumn(
+ unnestColumn,
+ "\"a\"",
+ ColumnType.STRING_ARRAY,
+ ExprMacroTable.nil()
+ );
+ Filter unnestEquals = new EqualityFilter(unnestColumn, ColumnType.STRING,
"value", null);
+ Filter bRange = new RangeFilter("b", ColumnType.LONG, 1L, 10L, false,
false, null);
+ CursorBuildSpec buildSpec = CursorBuildSpec.builder()
+
.setPhysicalColumns(Set.of(unnestColumn, "b", "c"))
+
.setGroupingColumns(List.of(unnestColumn, "b", "c"))
+ .setFilter(bRange)
+ .build();
+
+ UnnestCursorFactory.UnnestFilterSplit split =
UnnestCursorFactory.computeBaseAndPostUnnestFilters(
+ buildSpec.getFilter(),
+ unnestEquals,
+ buildSpec.getVirtualColumns(),
+ identifier,
+ "a",
+
ColumnCapabilitiesImpl.createDefault().setHasMultipleValues(true).setType(ColumnType.STRING)
+ );
+
+ // since unnest column is mvd, expect pushdown filter as on base table
+ CursorBuildSpec expected = CursorBuildSpec.builder()
+ .setPhysicalColumns(Set.of("a",
"b", "c"))
+
.setVirtualColumns(VirtualColumns.create(identifier))
+ .setFilter(
+ new AndFilter(
+ List.of(
+ bRange,
+ new
EqualityFilter("a", ColumnType.STRING, "value", null)
+ )
+ )
+ )
+ .build();
+
+ CursorBuildSpec transformed = UnnestCursorFactory.transformCursorBuildSpec(
+ buildSpec,
+ identifier,
+ split.getBaseTableFilter()
+ );
+
+ Assertions.assertEquals(expected, transformed);
+ }
+
+ @Test
+ public void testTransformCursorArray()
+ {
+ final String unnestColumn = "unnest";
+ ExpressionVirtualColumn array = new ExpressionVirtualColumn(
+ unnestColumn,
+ "array(x, y, z)",
+ ColumnType.DOUBLE_ARRAY,
+ ExprMacroTable.nil()
+ );
+ CursorBuildSpec buildSpec = CursorBuildSpec.builder()
+
.setPhysicalColumns(Set.of(unnestColumn))
+
.setGroupingColumns(List.of(unnestColumn))
+ .build();
+
+
+ CursorBuildSpec expected = CursorBuildSpec.builder()
+ .setPhysicalColumns(Set.of("x",
"y", "z"))
+
.setVirtualColumns(VirtualColumns.create(array))
+ .build();
+
+ CursorBuildSpec transformed = UnnestCursorFactory.transformCursorBuildSpec(
+ buildSpec,
+ array,
+ null
+ );
+
+ Assertions.assertEquals(expected, transformed);
+ }
+
public void testComputeBaseAndPostUnnestFilters(
Filter testQueryFilter,
String expectedBasePushDown,
@@ -858,16 +1045,18 @@ public class UnnestCursorFactoryTest extends
InitializedNullHandlingTest
)
{
final String inputColumn =
cursorFactory.getUnnestInputIfDirectAccess(cursorFactory.getUnnestColumn());
+ Assert.assertNotNull(inputColumn);
final VirtualColumn vc = cursorFactory.getUnnestColumn();
- Pair<Filter, Filter> filterPair =
cursorFactory.computeBaseAndPostUnnestFilters(
+ UnnestCursorFactory.UnnestFilterSplit filterSplit =
UnnestCursorFactory.computeBaseAndPostUnnestFilters(
testQueryFilter,
null,
VirtualColumns.EMPTY,
+ cursorFactory.getUnnestColumn(),
inputColumn,
vc.capabilities(cursorFactory, inputColumn)
);
- Filter actualPushDownFilter = filterPair.lhs;
- Filter actualPostUnnestFilter = filterPair.rhs;
+ Filter actualPushDownFilter = filterSplit.getBaseTableFilter();
+ Filter actualPostUnnestFilter = filterSplit.getPostUnnestFilter();
Assert.assertEquals(
"Expects only top level child of And Filter to push down to base",
expectedBasePushDown,
diff --git
a/processing/src/test/java/org/apache/druid/segment/projections/ProjectionsTest.java
b/processing/src/test/java/org/apache/druid/segment/projections/ProjectionsTest.java
index dc86fb8ab2f..b8922a9a3f1 100644
---
a/processing/src/test/java/org/apache/druid/segment/projections/ProjectionsTest.java
+++
b/processing/src/test/java/org/apache/druid/segment/projections/ProjectionsTest.java
@@ -56,6 +56,7 @@ class ProjectionsTest
12345
);
CursorBuildSpec cursorBuildSpec = CursorBuildSpec.builder()
+
.setPhysicalColumns(Set.of("c"))
.setPreferredOrdering(List.of())
.setAggregators(
List.of(
@@ -99,6 +100,7 @@ class ProjectionsTest
12345
);
CursorBuildSpec cursorBuildSpecNoFilter = CursorBuildSpec.builder()
+
.setPhysicalColumns(Set.of("c"))
.setPreferredOrdering(List.of())
.setAggregators(
List.of(
@@ -115,6 +117,7 @@ class ProjectionsTest
)
);
CursorBuildSpec cursorBuildSpecWithFilter = CursorBuildSpec.builder()
+
.setPhysicalColumns(Set.of("b", "c"))
.setPreferredOrdering(List.of())
.setFilter(
new
EqualityFilter(
@@ -166,6 +169,7 @@ class ProjectionsTest
);
CursorBuildSpec cursorBuildSpecNoFilter = CursorBuildSpec.builder()
.setPreferredOrdering(List.of())
+
.setPhysicalColumns(Set.of("a", "b", "c"))
.setGroupingColumns(List.of("a", "b"))
.setAggregators(
List.of(
@@ -182,6 +186,7 @@ class ProjectionsTest
)
);
CursorBuildSpec cursorBuildSpecWithFilter = CursorBuildSpec.builder()
+
.setPhysicalColumns(Set.of("a", "b", "c"))
.setGroupingColumns(List.of("a", "b"))
.setPreferredOrdering(List.of())
.setFilter(
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]