Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,9 @@ public class SqlExpressionBenchmark extends SqlBaseQueryBenchmark
"SELECT CASE WHEN MOD(long1, 2) = 0 THEN -1 WHEN MOD(long1, 2) = 1 THEN long2 / MOD(long1, 2) ELSE long3 END FROM expressions GROUP BY 1",
// cast
"SELECT CAST(string1 as BIGINT) + CAST(string3 as DOUBLE) + long3, COUNT(*) FROM expressions GROUP BY 1 ORDER BY 2",
"SELECT COUNT(*), SUM(CAST(string1 as BIGINT) + CAST(string3 as BIGINT)) FROM expressions WHERE double3 < 1010.0 AND double3 > 100.0"
"SELECT COUNT(*), SUM(CAST(string1 as BIGINT) + CAST(string3 as BIGINT)) FROM expressions WHERE double3 < 1010.0 AND double3 > 100.0",
// virtual-column bitmap-index
"SELECT COUNT(*) FROM expressions WHERE __time >= TIMESTAMP '2000-01-01 00:00:00' AND __time < TIMESTAMP '2000-01-02 00:00:00' AND (UPPER(COALESCE(string3,'')) LIKE '1%' OR TRIM(UPPER(COALESCE(string3,''))) LIKE '1%' OR SUBSTRING(UPPER(COALESCE(string3,'')),1,1) IN ('1','2','3','4','5') OR ('X' || UPPER(COALESCE(string3,''))) LIKE 'X1%') AND (UPPER(COALESCE(string5,'')) LIKE '2%' OR TRIM(UPPER(COALESCE(string5,''))) LIKE '2%' OR SUBSTRING(UPPER(COALESCE(string5,'')),1,1) IN ('1','2','3','4','5') OR ('Y' || UPPER(COALESCE(string5,''))) LIKE 'Y2%') AND CAST(double4 * 1000 AS BIGINT) BETWEEN -850000000 AND 850000000"
);

@Param({
Expand Down Expand Up @@ -233,10 +235,17 @@ public class SqlExpressionBenchmark extends SqlBaseQueryBenchmark
"57",
"58",
"59",
"60"
"60",
"61"
})
private String query;

@Param({
"0",
"100"
})
private String maxVirtualColumnsForBitmapIndexing;

@Override
public String getQuery()
{
Expand All @@ -255,7 +264,8 @@ protected Map<String, Object> getContext()
final Map<String, Object> context = ImmutableMap.of(
QueryContexts.VECTORIZE_KEY, vectorize,
QueryContexts.VECTORIZE_VIRTUAL_COLUMNS_KEY, vectorize,
GroupByQueryConfig.CTX_KEY_DEFER_EXPRESSION_DIMENSIONS, deferExpressionDimensions
GroupByQueryConfig.CTX_KEY_DEFER_EXPRESSION_DIMENSIONS, deferExpressionDimensions,
QueryContexts.CTX_MAX_VIRTUAL_COLUMNS_FOR_BITMAP, maxVirtualColumnsForBitmapIndexing
);
return context;
}
Expand Down
1 change: 1 addition & 0 deletions docs/querying/query-context-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ Unless otherwise noted, the following parameters apply to all query types, and t
|`sqlPlannerBloat`|`1000`|Calcite parameter which controls whether to merge two Project operators when inlining expressions causes complexity to increase. Implemented as a workaround to exception `There are not enough rules to produce a node with desired properties: convention=DRUID, sort=[]` thrown after rejecting the merge of two projects.|
|`cloneQueryMode`|`excludeClones`| Indicates whether clone Historicals should be queried by brokers. Clone servers are created by the `cloneServers` Coordinator dynamic configuration. Possible values are `excludeClones`, `includeClones` and `preferClones`. `excludeClones` means that clone Historicals are not queried by the broker. `preferClones` indicates that when given a choice between the clone Historical and the original Historical which is being cloned, the broker chooses the clones. Historicals which are not involved in the cloning process will still be queried. `includeClones` means that broker queries any Historical without regarding clone status. This parameter only affects native queries. MSQ does not query Historicals directly.|
|`realtimeSegmentsOnly` |`false`| When set to true, only query realtime segments. Historical segments are excluded. |
|`maxVirtualColumnsForBitmapIndexing`|`Integer.MAX_VALUE`| Sets the virtual-column count threshold beyond which Druid stops using bitmap indexes for filters on virtual columns.|

## Parameters by query type

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -777,4 +777,9 @@ public boolean isRealtimeSegmentsOnly()
{
return getBoolean(QueryContexts.REALTIME_SEGMENTS_ONLY, QueryContexts.DEFAULT_REALTIME_SEGMENTS_ONLY);
}

public int getMaxVirtualColumnsForBitmapIndexing()
{
return getInt(QueryContexts.CTX_MAX_VIRTUAL_COLUMNS_FOR_BITMAP, QueryContexts.DEFAULT_MAX_VIRTUAL_COLUMNS_FOR_BITMAP);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ public class QueryContexts
public static final boolean DEFAULT_REALTIME_SEGMENTS_ONLY = false;

public static final String CTX_PREPLANNED = "prePlanned";
public static final String CTX_MAX_VIRTUAL_COLUMNS_FOR_BITMAP = "maxVirtualColumnsForBitmapIndexing";

public static final boolean DEFAULT_PREPLANNED = true;

// Defaults
Expand Down Expand Up @@ -177,6 +179,7 @@ public class QueryContexts
public static final boolean DEFAULT_USE_NESTED_FOR_UNKNOWN_TYPE_IN_SUBQUERY = false;
public static final boolean DEFAULT_EXTENDED_FILTERED_SUM_REWRITE_ENABLED = true;
public static final boolean DEFAULT_CTX_FULL_REPORT = false;
public static final int DEFAULT_MAX_VIRTUAL_COLUMNS_FOR_BITMAP = Integer.MAX_VALUE;


@SuppressWarnings("unused") // Used by Jackson serialization
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public class QueryableIndexCursorHolder implements CursorHolder
private final QueryContext queryContext;
private final int vectorSize;
private final Supplier<CursorResources> resourcesSupplier;
private final boolean disableVirtualColumnBitmapIndexes;

public QueryableIndexCursorHolder(
QueryableIndex index,
Expand All @@ -108,6 +109,8 @@ public QueryableIndexCursorHolder(
this.queryContext = cursorBuildSpec.getQueryContext();
this.vectorSize = cursorBuildSpec.getQueryContext().getVectorSize();
this.metrics = cursorBuildSpec.getQueryMetrics();
this.disableVirtualColumnBitmapIndexes = queryContext.getMaxVirtualColumnsForBitmapIndexing()
< virtualColumns.getColumnNames().size();
this.resourcesSupplier = Suppliers.memoize(
() -> new CursorResources(
index,
Expand All @@ -117,7 +120,8 @@ public QueryableIndexCursorHolder(
interval,
filter,
cursorBuildSpec.getQueryContext().getBoolean(QueryContexts.CURSOR_AUTO_ARRANGE_FILTERS, true),
metrics
metrics,
disableVirtualColumnBitmapIndexes
)
);
}
Expand Down Expand Up @@ -672,14 +676,19 @@ private CursorResources(
Interval interval,
@Nullable Filter filter,
boolean cursorAutoArrangeFilters,
@Nullable QueryMetrics<? extends Query<?>> metrics
@Nullable QueryMetrics<? extends Query<?>> metrics,
boolean disableVirtualColumnBitmapIndexes
)
{
this.closer = Closer.create();
this.columnCache = new ColumnCache(index, virtualColumns, closer);
this.timeBoundaryInspector = timeBoundaryInspector;
try {
this.numRows = index.getNumRows();
final ColumnIndexSelector indexSelectorForFilters =
disableVirtualColumnBitmapIndexes
? new VirtualColumnBitmapDisablingIndexSelector(columnCache, virtualColumns)
: columnCache;
this.filterBundle = makeFilterBundle(
computeFilterWithIntervalIfNeeded(
timeBoundaryInspector,
Expand All @@ -688,7 +697,7 @@ private CursorResources(
filter
),
cursorAutoArrangeFilters,
columnCache,
indexSelectorForFilters,
numRows,
metrics
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* 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.druid.segment;

import org.apache.druid.collections.bitmap.BitmapFactory;
import org.apache.druid.query.filter.ColumnIndexSelector;
import org.apache.druid.segment.column.ColumnCapabilities;
import org.apache.druid.segment.column.ColumnHolder;
import org.apache.druid.segment.column.ColumnIndexSupplier;
import org.apache.druid.segment.column.SelectableColumn;
import org.apache.druid.segment.selector.settable.SettableColumnValueSelector;
import org.apache.druid.segment.serde.NoIndexesColumnIndexSupplier;

import javax.annotation.Nullable;
import java.util.Objects;

public final class VirtualColumnBitmapDisablingIndexSelector implements ColumnIndexSelector
{
private static final ColumnIndexSupplier NO_INDEXES = NoIndexesColumnIndexSupplier.getInstance();
private final ColumnIndexSelector delegate;
private final VirtualColumns virtualColumns;


public VirtualColumnBitmapDisablingIndexSelector(
final ColumnIndexSelector delegate,
final VirtualColumns virtualColumns
)
{
this.delegate = Objects.requireNonNull(delegate, "delegate");
this.virtualColumns = Objects.requireNonNull(virtualColumns, "virtualColumns");
}

@Override
public int getNumRows()
{
return delegate.getNumRows();
}

@Override
public BitmapFactory getBitmapFactory()
{
return delegate.getBitmapFactory();
}

@Override
@Nullable
public ColumnHolder getColumnHolder(final String columnName)
{
final ColumnHolder holder = delegate.getColumnHolder(columnName);
if (holder == null || !isVirtual(columnName)) {
return holder;
}

// force no indexes even if callers go via getColumnHolder().
return new ColumnHolder()
{
@Override
public ColumnCapabilities getCapabilities()
{
return holder.getCapabilities();
}

@Override
public int getLength()
{
return holder.getLength();
}

@Override
public SelectableColumn getColumn()
{
return holder.getColumn();
}

@Override
public ColumnIndexSupplier getIndexSupplier()
{
return NO_INDEXES;
}

@Override
public SettableColumnValueSelector makeNewSettableColumnValueSelector()
{
return holder.makeNewSettableColumnValueSelector();
}
};
}

@Override
@Nullable
public ColumnIndexSupplier getIndexSupplier(final String column)
{
if (column.isEmpty()) {
return null;
}

// Only disable indexes for virtual columns
if (isVirtual(column)) {
return NO_INDEXES;
}
return delegate.getIndexSupplier(column);
}


private boolean isVirtual(final String columnName)
{
return virtualColumns.getVirtualColumn(columnName) != null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* 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.druid.segment.filter;

import com.google.common.collect.ImmutableList;
import org.apache.druid.collections.bitmap.BitmapFactory;
import org.apache.druid.java.util.common.io.Closer;
import org.apache.druid.math.expr.ExprMacroTable;
import org.apache.druid.query.DefaultBitmapResultFactory;
import org.apache.druid.query.filter.ColumnIndexSelector;
import org.apache.druid.query.filter.EqualityFilter;
import org.apache.druid.query.filter.Filter;
import org.apache.druid.query.filter.FilterBundle;
import org.apache.druid.segment.ColumnCache;
import org.apache.druid.segment.QueryableIndex;
import org.apache.druid.segment.TestIndex;
import org.apache.druid.segment.VirtualColumnBitmapDisablingIndexSelector;
import org.apache.druid.segment.VirtualColumns;
import org.apache.druid.segment.column.ColumnType;
import org.apache.druid.segment.virtual.ExpressionVirtualColumn;
import org.apache.druid.testing.InitializedNullHandlingTest;
import org.junit.Assert;
import org.junit.Test;

import java.io.IOException;

public class FilterBundleVCBitmapIndexDisablingTest extends InitializedNullHandlingTest
{

@Test
public void testVCBitmapIndexEnabled()
{
final VirtualColumns virtualColumns = VirtualColumns.create(ImmutableList.of(
new ExpressionVirtualColumn("v1",
"countryName", ColumnType.STRING,
ExprMacroTable.nil()
)
));
final QueryableIndex index = TestIndex.getMMappedWikipediaIndex();
BitmapFactory bitmapFactory = index.getBitmapFactoryForDimensions();

try (Closer closer = Closer.create()) {
ColumnCache columnCache = new ColumnCache(index, virtualColumns, closer);
VirtualColumnBitmapDisablingIndexSelector selector = new VirtualColumnBitmapDisablingIndexSelector(columnCache,
virtualColumns
);

final FilterBundle filterBundleIndexEnabled = makeFilterBundle(new AndFilter(ImmutableList.of(
new EqualityFilter("v1", ColumnType.STRING, "United States", null),
new EqualityFilter("countryName",
ColumnType.STRING,
"United States",
null
)
)), columnCache, bitmapFactory);

final FilterBundle filterBundleIndexDisabled = makeFilterBundle(new AndFilter(ImmutableList.of(
new EqualityFilter("v1", ColumnType.STRING, "United States", null),
new EqualityFilter("countryName",
ColumnType.STRING,
"United States",
null
)
)), selector, bitmapFactory);

Assert.assertEquals(2, filterBundleIndexEnabled.getIndex().getIndexInfo().getIndexes().size());
Assert.assertEquals("v1 = United States", filterBundleIndexEnabled.getIndex().getIndexInfo().getIndexes().get(0).getFilter());
Assert.assertEquals("countryName = United States", filterBundleIndexEnabled.getIndex().getIndexInfo().getIndexes().get(1).getFilter());

Assert.assertNull(filterBundleIndexDisabled.getIndex().getIndexInfo().getIndexes());
Assert.assertEquals("countryName = United States", filterBundleIndexDisabled.getIndex().getIndexInfo().getFilter());
}
catch (IOException e) {
throw new RuntimeException(e);
}

}

protected FilterBundle makeFilterBundle(
final Filter filter,
ColumnIndexSelector selector,
BitmapFactory bitmapFactory
)
{
return new FilterBundle.Builder(filter, selector, false).build(new DefaultBitmapResultFactory(bitmapFactory),
selector.getNumRows(),
selector.getNumRows(),
false
);
}
}
Loading
Loading