This is an automated email from the ASF dual-hosted git repository.
gian 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 c3f543c225c improve filter bundle build for not/istrue/isfalse (#18491)
c3f543c225c is described below
commit c3f543c225cc69414dae797d23f81498e5410208
Author: Clint Wylie <[email protected]>
AuthorDate: Sat Sep 6 16:52:51 2025 -0700
improve filter bundle build for not/istrue/isfalse (#18491)
---
.../druid/query/filter/BooleanUnaryFilter.java | 36 ++++++
.../apache/druid/query/filter/FilterBundle.java | 10 ++
.../org/apache/druid/segment/filter/AndFilter.java | 2 +-
.../druid/segment/filter/IsBooleanFilter.java | 142 ++++++++++++---------
.../org/apache/druid/segment/filter/NotFilter.java | 118 +++++++++--------
.../org/apache/druid/segment/filter/OrFilter.java | 2 +-
6 files changed, 194 insertions(+), 116 deletions(-)
diff --git
a/processing/src/main/java/org/apache/druid/query/filter/BooleanUnaryFilter.java
b/processing/src/main/java/org/apache/druid/query/filter/BooleanUnaryFilter.java
new file mode 100644
index 00000000000..d1402bcde31
--- /dev/null
+++
b/processing/src/main/java/org/apache/druid/query/filter/BooleanUnaryFilter.java
@@ -0,0 +1,36 @@
+/*
+ * 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.query.filter;
+
+import org.apache.druid.segment.index.BitmapColumnIndex;
+
+import javax.annotation.Nullable;
+
+public interface BooleanUnaryFilter extends Filter
+{
+ Filter getBaseFilter();
+
+ /**
+ * Specialized alternative to {@link
#getBitmapColumnIndex(ColumnIndexSelector)} to allow reuse of
+ * {@link BitmapColumnIndex} created as part of a {@link
FilterBundle.Builder}
+ */
+ @Nullable
+ BitmapColumnIndex getBitmapColumnIndex(int numRows, FilterBundle.Builder
baseBuilder);
+}
diff --git
a/processing/src/main/java/org/apache/druid/query/filter/FilterBundle.java
b/processing/src/main/java/org/apache/druid/query/filter/FilterBundle.java
index 51db678684a..337714013b1 100644
--- a/processing/src/main/java/org/apache/druid/query/filter/FilterBundle.java
+++ b/processing/src/main/java/org/apache/druid/query/filter/FilterBundle.java
@@ -178,6 +178,16 @@ public class FilterBundle
childBuilders.add(new FilterBundle.Builder(childFilter,
columnIndexSelector, cursorAutoArrangeFilters));
}
this.bitmapColumnIndex =
bool.getBitmapColumnIndex(columnIndexSelector.getBitmapFactory(),
childBuilders);
+ } else if (filter instanceof BooleanUnaryFilter) {
+ final BooleanUnaryFilter bool = (BooleanUnaryFilter) filter;
+ childBuilders = new ArrayList<>(1);
+ final FilterBundle.Builder childBuilder = new FilterBundle.Builder(
+ bool.getBaseFilter(),
+ columnIndexSelector,
+ cursorAutoArrangeFilters
+ );
+ childBuilders.add(childBuilder);
+ this.bitmapColumnIndex =
bool.getBitmapColumnIndex(columnIndexSelector.getNumRows(), childBuilder);
} else {
this.childBuilders = List.of();
this.bitmapColumnIndex =
filter.getBitmapColumnIndex(columnIndexSelector);
diff --git
a/processing/src/main/java/org/apache/druid/segment/filter/AndFilter.java
b/processing/src/main/java/org/apache/druid/segment/filter/AndFilter.java
index 57cb233000d..e1c96d4ae08 100644
--- a/processing/src/main/java/org/apache/druid/segment/filter/AndFilter.java
+++ b/processing/src/main/java/org/apache/druid/segment/filter/AndFilter.java
@@ -152,7 +152,7 @@ public class AndFilter implements BooleanFilter
@Override
public int estimatedComputeCost()
{
- // There's no additional cost on AND filter, cost in child filters
would be summed.
+ // There's no additional cost on AND filter, cost in child
FilterBundle.Builder will be summed
return 0;
}
diff --git
a/processing/src/main/java/org/apache/druid/segment/filter/IsBooleanFilter.java
b/processing/src/main/java/org/apache/druid/segment/filter/IsBooleanFilter.java
index 792b305cccb..c41472107a0 100644
---
a/processing/src/main/java/org/apache/druid/segment/filter/IsBooleanFilter.java
+++
b/processing/src/main/java/org/apache/druid/segment/filter/IsBooleanFilter.java
@@ -21,8 +21,10 @@ package org.apache.druid.segment.filter;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.query.BitmapResultFactory;
+import org.apache.druid.query.filter.BooleanUnaryFilter;
import org.apache.druid.query.filter.ColumnIndexSelector;
import org.apache.druid.query.filter.Filter;
+import org.apache.druid.query.filter.FilterBundle;
import org.apache.druid.query.filter.ValueMatcher;
import org.apache.druid.query.filter.vector.BaseVectorValueMatcher;
import org.apache.druid.query.filter.vector.ReadableVectorMatch;
@@ -51,7 +53,7 @@ import java.util.Set;
* @see org.apache.druid.query.filter.IsTrueDimFilter
* @see org.apache.druid.query.filter.IsFalseDimFilter
*/
-public class IsBooleanFilter implements Filter
+public class IsBooleanFilter implements BooleanUnaryFilter
{
private final Filter baseFilter;
private final boolean isTrue;
@@ -67,6 +69,7 @@ public class IsBooleanFilter implements Filter
return isTrue;
}
+ @Override
public Filter getBaseFilter()
{
return baseFilter;
@@ -74,70 +77,16 @@ public class IsBooleanFilter implements Filter
@Nullable
@Override
- public BitmapColumnIndex getBitmapColumnIndex(ColumnIndexSelector selector)
+ public BitmapColumnIndex getBitmapColumnIndex(int numRows,
FilterBundle.Builder baseBuilder)
{
- final BitmapColumnIndex baseIndex =
baseFilter.getBitmapColumnIndex(selector);
- if (baseIndex != null && (isTrue ||
baseIndex.getIndexCapabilities().isInvertible())) {
- return new BitmapColumnIndex()
- {
- @Override
- public ColumnIndexCapabilities getIndexCapabilities()
- {
- return baseIndex.getIndexCapabilities();
- }
-
- @Override
- public int estimatedComputeCost()
- {
- return baseIndex.estimatedComputeCost();
- }
-
- @Override
- public <T> T computeBitmapResult(BitmapResultFactory<T>
bitmapResultFactory, boolean includeUnknown)
- {
- if (isTrue) {
- return baseIndex.computeBitmapResult(bitmapResultFactory, false);
- }
- return bitmapResultFactory.complement(
- baseIndex.computeBitmapResult(bitmapResultFactory, true),
- selector.getNumRows()
- );
- }
-
- @Nullable
- @Override
- public <T> T computeBitmapResult(
- BitmapResultFactory<T> bitmapResultFactory,
- int applyRowCount,
- int totalRowCount,
- boolean includeUnknown
- )
- {
- if (isTrue) {
- return baseIndex.computeBitmapResult(
- bitmapResultFactory,
- applyRowCount,
- totalRowCount,
- false
- );
- }
-
- final T result = baseIndex.computeBitmapResult(
- bitmapResultFactory,
- applyRowCount,
- totalRowCount,
- true
- );
-
- if (result == null) {
- return null;
- }
+ return getBitmapColumnIndex(numRows, isTrue,
baseBuilder.getBitmapColumnIndex());
+ }
- return bitmapResultFactory.complement(result, selector.getNumRows());
- }
- };
- }
- return null;
+ @Nullable
+ @Override
+ public BitmapColumnIndex getBitmapColumnIndex(ColumnIndexSelector selector)
+ {
+ return getBitmapColumnIndex(selector.getNumRows(), isTrue,
baseFilter.getBitmapColumnIndex(selector));
}
@Override
@@ -238,4 +187,71 @@ public class IsBooleanFilter implements Filter
// to return a different hash from baseFilter
return Objects.hash(1, baseFilter, isTrue);
}
+
+ @Nullable
+ private static BitmapColumnIndex getBitmapColumnIndex(int numRows, boolean
isTrue, BitmapColumnIndex baseIndex)
+ {
+ if (baseIndex != null && (isTrue ||
baseIndex.getIndexCapabilities().isInvertible())) {
+ return new BitmapColumnIndex()
+ {
+ @Override
+ public ColumnIndexCapabilities getIndexCapabilities()
+ {
+ return baseIndex.getIndexCapabilities();
+ }
+
+ @Override
+ public int estimatedComputeCost()
+ {
+ // There's no additional cost on is boolean filter, cost will come
from child FilterBundle.Builder
+ return 0;
+ }
+
+ @Override
+ public <T> T computeBitmapResult(BitmapResultFactory<T>
bitmapResultFactory, boolean includeUnknown)
+ {
+ if (isTrue) {
+ return baseIndex.computeBitmapResult(bitmapResultFactory, false);
+ }
+ return bitmapResultFactory.complement(
+ baseIndex.computeBitmapResult(bitmapResultFactory, true),
+ numRows
+ );
+ }
+
+ @Nullable
+ @Override
+ public <T> T computeBitmapResult(
+ BitmapResultFactory<T> bitmapResultFactory,
+ int applyRowCount,
+ int totalRowCount,
+ boolean includeUnknown
+ )
+ {
+ if (isTrue) {
+ return baseIndex.computeBitmapResult(
+ bitmapResultFactory,
+ applyRowCount,
+ totalRowCount,
+ false
+ );
+ }
+
+ final T result = baseIndex.computeBitmapResult(
+ bitmapResultFactory,
+ applyRowCount,
+ totalRowCount,
+ true
+ );
+
+ if (result == null) {
+ return null;
+ }
+
+ return bitmapResultFactory.complement(result, numRows);
+ }
+ };
+ }
+ return null;
+ }
}
diff --git
a/processing/src/main/java/org/apache/druid/segment/filter/NotFilter.java
b/processing/src/main/java/org/apache/druid/segment/filter/NotFilter.java
index 52e66d561e8..4ce5d15c098 100644
--- a/processing/src/main/java/org/apache/druid/segment/filter/NotFilter.java
+++ b/processing/src/main/java/org/apache/druid/segment/filter/NotFilter.java
@@ -21,8 +21,10 @@ package org.apache.druid.segment.filter;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.query.BitmapResultFactory;
+import org.apache.druid.query.filter.BooleanUnaryFilter;
import org.apache.druid.query.filter.ColumnIndexSelector;
import org.apache.druid.query.filter.Filter;
+import org.apache.druid.query.filter.FilterBundle;
import org.apache.druid.query.filter.ValueMatcher;
import org.apache.druid.query.filter.vector.BaseVectorValueMatcher;
import org.apache.druid.query.filter.vector.ReadableVectorMatch;
@@ -42,18 +44,18 @@ import java.util.Set;
/**
* Nice filter you have there... NOT!
- *
+ * <p>
* This filter inverts the {@code includeUnknown} flag to properly ap Druids
native two-valued logic (true, false) to
* SQL three-valued logic (true, false, unknown). At the top level, this flag
is always passed in as 'false', and is
* only flipped by this filter. Other logical filters ({@link AndFilter} and
{@link OrFilter}) propagate the value of
* {@code includeUnknown} to their children.
- *
+ * <p>
* For example, if the base filter is equality, by default value matchers and
indexes only return true for the rows
* that are equal to the value. When wrapped in a not filter, the not filter
indicates that the equality matchers and
* indexes should also include the null or 'unknown' values as matches, so
that inverting the match does not incorrectly
* include these null values as matches.
*/
-public class NotFilter implements Filter
+public class NotFilter implements BooleanUnaryFilter
{
private final Filter baseFilter;
@@ -64,56 +66,16 @@ public class NotFilter implements Filter
@Nullable
@Override
- public BitmapColumnIndex getBitmapColumnIndex(ColumnIndexSelector selector)
+ public BitmapColumnIndex getBitmapColumnIndex(int numRows,
FilterBundle.Builder baseBuilder)
{
- final BitmapColumnIndex baseIndex =
baseFilter.getBitmapColumnIndex(selector);
- if (baseIndex != null && baseIndex.getIndexCapabilities().isInvertible()) {
- return new BitmapColumnIndex()
- {
- @Override
- public ColumnIndexCapabilities getIndexCapabilities()
- {
- return baseIndex.getIndexCapabilities();
- }
-
- @Override
- public int estimatedComputeCost()
- {
- return baseIndex.estimatedComputeCost();
- }
-
- @Override
- public <T> T computeBitmapResult(BitmapResultFactory<T>
bitmapResultFactory, boolean includeUnknown)
- {
- return bitmapResultFactory.complement(
- baseIndex.computeBitmapResult(bitmapResultFactory,
!includeUnknown),
- selector.getNumRows()
- );
- }
+ return getBitmapColumnIndex(numRows, baseBuilder.getBitmapColumnIndex());
+ }
- @Nullable
- @Override
- public <T> T computeBitmapResult(
- BitmapResultFactory<T> bitmapResultFactory,
- int applyRowCount,
- int totalRowCount,
- boolean includeUnknown
- )
- {
- final T result = baseIndex.computeBitmapResult(
- bitmapResultFactory,
- applyRowCount,
- totalRowCount,
- !includeUnknown
- );
- if (result == null) {
- return null;
- }
- return bitmapResultFactory.complement(result, selector.getNumRows());
- }
- };
- }
- return null;
+ @Nullable
+ @Override
+ public BitmapColumnIndex getBitmapColumnIndex(ColumnIndexSelector selector)
+ {
+ return getBitmapColumnIndex(selector.getNumRows(),
baseFilter.getBitmapColumnIndex(selector));
}
@Override
@@ -209,8 +171,62 @@ public class NotFilter implements Filter
return Objects.hash(1, baseFilter);
}
+ @Override
public Filter getBaseFilter()
{
return baseFilter;
}
+
+ @Nullable
+ private static BitmapColumnIndex getBitmapColumnIndex(int numRows,
BitmapColumnIndex baseIndex)
+ {
+ if (baseIndex != null && baseIndex.getIndexCapabilities().isInvertible()) {
+ return new BitmapColumnIndex()
+ {
+ @Override
+ public ColumnIndexCapabilities getIndexCapabilities()
+ {
+ return baseIndex.getIndexCapabilities();
+ }
+
+ @Override
+ public int estimatedComputeCost()
+ {
+ // There's no additional cost on NOT filter, cost will come from
child FilterBundle.Builder
+ return 0;
+ }
+
+ @Override
+ public <T> T computeBitmapResult(BitmapResultFactory<T>
bitmapResultFactory, boolean includeUnknown)
+ {
+ return bitmapResultFactory.complement(
+ baseIndex.computeBitmapResult(bitmapResultFactory,
!includeUnknown),
+ numRows
+ );
+ }
+
+ @Nullable
+ @Override
+ public <T> T computeBitmapResult(
+ BitmapResultFactory<T> bitmapResultFactory,
+ int applyRowCount,
+ int totalRowCount,
+ boolean includeUnknown
+ )
+ {
+ final T result = baseIndex.computeBitmapResult(
+ bitmapResultFactory,
+ applyRowCount,
+ totalRowCount,
+ !includeUnknown
+ );
+ if (result == null) {
+ return null;
+ }
+ return bitmapResultFactory.complement(result, numRows);
+ }
+ };
+ }
+ return null;
+ }
}
diff --git
a/processing/src/main/java/org/apache/druid/segment/filter/OrFilter.java
b/processing/src/main/java/org/apache/druid/segment/filter/OrFilter.java
index dd68dc40c64..53e37036336 100644
--- a/processing/src/main/java/org/apache/druid/segment/filter/OrFilter.java
+++ b/processing/src/main/java/org/apache/druid/segment/filter/OrFilter.java
@@ -473,7 +473,7 @@ public class OrFilter implements BooleanFilter
@Override
public int estimatedComputeCost()
{
- // There's no additional cost on OR filter, cost in child filters
would be summed.
+ // There's no additional cost on OR filter, cost in child
FilterBundle.Builder will be summed
return 0;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]