This is an automated email from the ASF dual-hosted git repository.

adarshsanjeev pushed a commit to branch 32.0.0
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/32.0.0 by this push:
     new 532fda5e0ad  [Backport] fix search query to check for the specific 
type of indexes it requires instead of using capabilities
532fda5e0ad is described below

commit 532fda5e0ad7deb3bdf1687199ffc523f8a4d5fd
Author: Clint Wylie <[email protected]>
AuthorDate: Mon Jan 27 20:59:36 2025 -0800

     [Backport] fix search query to check for the specific type of indexes it 
requires instead of using capabilities
    
    * fix search query to check for the specific type of indexes it requires 
instead of using capabilities
---
 .../druid/query/search/UseIndexesStrategy.java     | 107 ++++++++++-----------
 .../druid/query/search/SearchQueryRunnerTest.java  |  29 ++++++
 2 files changed, 80 insertions(+), 56 deletions(-)

diff --git 
a/processing/src/main/java/org/apache/druid/query/search/UseIndexesStrategy.java
 
b/processing/src/main/java/org/apache/druid/query/search/UseIndexesStrategy.java
index bd33d7f9783..32895eeaf88 100644
--- 
a/processing/src/main/java/org/apache/druid/query/search/UseIndexesStrategy.java
+++ 
b/processing/src/main/java/org/apache/druid/query/search/UseIndexesStrategy.java
@@ -25,7 +25,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntRBTreeMap;
 import org.apache.druid.collections.bitmap.BitmapFactory;
 import org.apache.druid.collections.bitmap.ImmutableBitmap;
 import org.apache.druid.collections.bitmap.MutableBitmap;
-import org.apache.druid.java.util.common.Pair;
+import org.apache.druid.java.util.common.NonnullPair;
 import org.apache.druid.query.DefaultBitmapResultFactory;
 import org.apache.druid.query.Order;
 import org.apache.druid.query.dimension.DimensionSpec;
@@ -35,23 +35,21 @@ import org.apache.druid.query.filter.ColumnIndexSelector;
 import org.apache.druid.query.filter.Filter;
 import org.apache.druid.query.search.CursorOnlyStrategy.CursorBasedExecutor;
 import org.apache.druid.segment.ColumnSelectorColumnIndexSelector;
-import org.apache.druid.segment.CursorFactory;
 import org.apache.druid.segment.Cursors;
 import org.apache.druid.segment.DeprecatedQueryableIndexColumnSelector;
 import org.apache.druid.segment.QueryableIndex;
 import org.apache.druid.segment.Segment;
 import org.apache.druid.segment.VirtualColumns;
-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.NumericColumn;
 import org.apache.druid.segment.index.BitmapColumnIndex;
 import 
org.apache.druid.segment.index.semantic.DictionaryEncodedStringValueIndex;
-import org.apache.druid.segment.virtual.VirtualizedColumnInspector;
 import org.joda.time.Interval;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 public class UseIndexesStrategy extends SearchStrategy
@@ -74,67 +72,64 @@ public class UseIndexesStrategy extends SearchStrategy
   public List<SearchQueryExecutor> getExecutionPlan(SearchQuery query, Segment 
segment)
   {
     final ImmutableList.Builder<SearchQueryExecutor> builder = 
ImmutableList.builder();
-    final QueryableIndex index = segment.as(QueryableIndex.class);
-    final CursorFactory cursorFactory = segment.asCursorFactory();
     final List<DimensionSpec> searchDims = getDimsToSearch(segment, 
query.getDimensions());
 
-    if (index != null) {
-      // pair of bitmap dims and non-bitmap dims
-      final Pair<List<DimensionSpec>, List<DimensionSpec>> pair = 
partitionDimensionList(
-          segment,
-          cursorFactory,
-          query.getVirtualColumns(),
-          searchDims
-      );
-      final List<DimensionSpec> bitmapSuppDims = pair.lhs;
-      final List<DimensionSpec> nonBitmapSuppDims = pair.rhs;
+    final QueryableIndex index = segment.as(QueryableIndex.class);
+    if (index == null) {
+      return Collections.singletonList(new CursorBasedExecutor(query, segment, 
searchDims));
+    }
 
-      if (bitmapSuppDims.size() > 0) {
-        final ColumnIndexSelector selector = new 
ColumnSelectorColumnIndexSelector(
-            index.getBitmapFactoryForDimensions(),
+    final ColumnIndexSelector selector = new ColumnSelectorColumnIndexSelector(
+        index.getBitmapFactoryForDimensions(),
+        query.getVirtualColumns(),
+        new DeprecatedQueryableIndexColumnSelector(index)
+    );
+
+    // pair of bitmap dims and non-bitmap dims
+    final NonnullPair<List<DimensionSpec>, List<DimensionSpec>> pair = 
partitionDimensionList(
+        segment,
+        selector,
+        searchDims
+    );
+    final List<DimensionSpec> bitmapSuppDims = pair.lhs;
+    final List<DimensionSpec> nonBitmapSuppDims = pair.rhs;
+
+    if (!bitmapSuppDims.isEmpty()) {
+      // Index-only plan is used only when any filter is not specified or the 
filter supports bitmap indexes.
+      //
+      // Note: if some filters support bitmap indexes but others are not, the 
current implementation always employs
+      // the cursor-based plan. This can be more optimized. One possible 
optimization is generating a bitmap index
+      // from the non-bitmap-support filter, and then use it to compute the 
filtered result by intersecting bitmaps.
+      if ((filter == null || filter.getBitmapColumnIndex(selector) != null)
+          && Cursors.getTimeOrdering(index.getOrdering()) == Order.ASCENDING) {
+        final ImmutableBitmap timeFilteredBitmap = makeTimeFilteredBitmap(
+            index,
+            segment,
             query.getVirtualColumns(),
-            new DeprecatedQueryableIndexColumnSelector(index)
+            filter,
+            interval
         );
-
-        // Index-only plan is used only when any filter is not specified or 
the filter supports bitmap indexes.
-        //
-        // Note: if some filters support bitmap indexes but others are not, 
the current implementation always employs
-        // the cursor-based plan. This can be more optimized. One possible 
optimization is generating a bitmap index
-        // from the non-bitmap-support filter, and then use it to compute the 
filtered result by intersecting bitmaps.
-        if ((filter == null || filter.getBitmapColumnIndex(selector) != null)
-            && Cursors.getTimeOrdering(index.getOrdering()) == 
Order.ASCENDING) {
-          final ImmutableBitmap timeFilteredBitmap = makeTimeFilteredBitmap(
-              index,
-              segment,
-              query.getVirtualColumns(),
-              filter,
-              interval
-          );
-          builder.add(new IndexOnlyExecutor(query, segment, 
timeFilteredBitmap, bitmapSuppDims));
-        } else {
-          // Fall back to cursor-based execution strategy
-          nonBitmapSuppDims.addAll(bitmapSuppDims);
-        }
+        builder.add(new IndexOnlyExecutor(query, segment, timeFilteredBitmap, 
bitmapSuppDims));
+      } else {
+        // Fall back to cursor-based execution strategy
+        nonBitmapSuppDims.addAll(bitmapSuppDims);
       }
+    }
 
-      if (nonBitmapSuppDims.size() > 0) {
-        builder.add(new CursorBasedExecutor(query, segment, 
nonBitmapSuppDims));
-      }
-    } else {
-      builder.add(new CursorBasedExecutor(query, segment, searchDims));
+    if (!nonBitmapSuppDims.isEmpty()) {
+      builder.add(new CursorBasedExecutor(query, segment, nonBitmapSuppDims));
     }
 
     return builder.build();
   }
 
   /**
-   * Split the given dimensions list into bitmap-supporting dimensions and 
non-bitmap supporting ones.
-   * Note that the returned lists are free to modify.
+   * Split the given dimensions list into columns which provide {@link 
DictionaryEncodedStringValueIndex} and those
+   * which do not. Note that the returned lists are free to modify.
    */
-  private static Pair<List<DimensionSpec>, List<DimensionSpec>> 
partitionDimensionList(
+  private static NonnullPair<List<DimensionSpec>, List<DimensionSpec>> 
partitionDimensionList(
       Segment segment,
-      CursorFactory cursorFactory,
-      VirtualColumns virtualColumns,
+      ColumnIndexSelector columnIndexSelector,
       List<DimensionSpec> dimensions
   )
   {
@@ -144,22 +139,21 @@ public class UseIndexesStrategy extends SearchStrategy
         segment,
         dimensions
     );
-    VirtualizedColumnInspector columnInspector = new 
VirtualizedColumnInspector(cursorFactory, virtualColumns);
-
     for (DimensionSpec spec : dimsToSearch) {
-      ColumnCapabilities capabilities = 
columnInspector.getColumnCapabilities(spec.getDimension());
-      if (capabilities == null) {
+      ColumnIndexSupplier indexSupplier = 
columnIndexSelector.getIndexSupplier(spec.getDimension());
+      if (indexSupplier == null) {
+        // column doesn't exist, ignore it
         continue;
       }
 
-      if (capabilities.hasBitmapIndexes()) {
+      if (indexSupplier.as(DictionaryEncodedStringValueIndex.class) != null) {
         bitmapDims.add(spec);
       } else {
         nonBitmapDims.add(spec);
       }
     }
 
-    return new Pair<>(bitmapDims, nonBitmapDims);
+    return new NonnullPair<>(bitmapDims, nonBitmapDims);
   }
 
   static ImmutableBitmap makeTimeFilteredBitmap(
@@ -304,6 +298,7 @@ public class UseIndexesStrategy extends SearchStrategy
             }
           }
         } else {
+          // these were checked to be non-null in partitionDimensionList
           final DictionaryEncodedStringValueIndex bitmapIndex =
               indexSupplier.as(DictionaryEncodedStringValueIndex.class);
           for (int i = 0; i < bitmapIndex.getCardinality(); ++i) {
diff --git 
a/processing/src/test/java/org/apache/druid/query/search/SearchQueryRunnerTest.java
 
b/processing/src/test/java/org/apache/druid/query/search/SearchQueryRunnerTest.java
index fa8fb02ffcb..1b0012560bb 100644
--- 
a/processing/src/test/java/org/apache/druid/query/search/SearchQueryRunnerTest.java
+++ 
b/processing/src/test/java/org/apache/druid/query/search/SearchQueryRunnerTest.java
@@ -40,6 +40,7 @@ import org.apache.druid.query.Result;
 import org.apache.druid.query.context.ResponseContext;
 import org.apache.druid.query.dimension.DefaultDimensionSpec;
 import org.apache.druid.query.dimension.ExtractionDimensionSpec;
+import org.apache.druid.query.expression.TestExprMacroTable;
 import org.apache.druid.query.extraction.ExtractionFn;
 import org.apache.druid.query.extraction.JavaScriptExtractionFn;
 import org.apache.druid.query.extraction.MapLookupExtractor;
@@ -60,6 +61,7 @@ import org.apache.druid.segment.column.ColumnType;
 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.virtual.ExpressionVirtualColumn;
 import org.apache.druid.segment.virtual.ListFilteredVirtualColumn;
 import org.apache.druid.testing.InitializedNullHandlingTest;
 import org.apache.druid.timeline.SegmentId;
@@ -827,6 +829,33 @@ public class SearchQueryRunnerTest extends 
InitializedNullHandlingTest
     checkSearchQuery(searchQuery, expectedHits);
   }
 
+  @Test
+  public void testSearchVirtualColumns()
+  {
+    List<SearchHit> expectedHits = new ArrayList<>();
+    expectedHits.add(new SearchHit("vquality", "a", 93));
+    expectedHits.add(new SearchHit("vquality", "not a", 1116));
+
+    checkSearchQuery(
+        Druids.newSearchQueryBuilder()
+              .dataSource(QueryRunnerTestHelper.DATA_SOURCE)
+              .granularity(QueryRunnerTestHelper.ALL_GRAN)
+              .virtualColumns(
+                  new ExpressionVirtualColumn(
+                      "vquality",
+                      "case_searched(like(quality,'a%'), 'a', 'not a')",
+                      ColumnType.STRING,
+                      TestExprMacroTable.INSTANCE
+                  )
+              )
+              .dimensions("vquality")
+              .intervals(QueryRunnerTestHelper.FULL_ON_INTERVAL_SPEC)
+              .query("")
+              .build(),
+        expectedHits
+    );
+  }
+
   private void checkSearchQuery(Query searchQuery, List<SearchHit> 
expectedResults)
   {
     checkSearchQuery(searchQuery, runner, expectedResults);


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to