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

abhishek 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 358892e5b03 add nested array index support, fix some bugs (#15752)
358892e5b03 is described below

commit 358892e5b035b3f530f84976ce83acb1443ea539
Author: Clint Wylie <[email protected]>
AuthorDate: Mon Feb 5 01:42:09 2024 -0800

    add nested array index support, fix some bugs (#15752)
    
    This PR wires up ValueIndexes and ArrayElementIndexes for nested arrays, 
ValueIndexes for nested long and double columns, and fixes a handful of bugs I 
found after adding nested columns to the filter test gauntlet.
---
 .../java/org/apache/druid/math/expr/ExprEval.java  |   2 +-
 .../org/apache/druid/query/filter/NullFilter.java  |   2 +-
 .../org/apache/druid/query/filter/RangeFilter.java |  12 +-
 .../nested/CompressedNestedDataComplexColumn.java  |   2 +
 .../nested/NestedFieldColumnIndexSupplier.java     | 348 ++++++++++++++++-
 .../filter/ArrayContainsElementFilterTests.java    | 417 ++++++++++++++++++++-
 .../druid/segment/filter/BaseFilterTest.java       | 100 ++++-
 .../druid/segment/filter/EqualityFilterTests.java  | 414 +++++++++++++++++++-
 .../druid/segment/filter/RangeFilterTests.java     | 215 ++++++++++-
 .../nested/NestedFieldColumnIndexSupplierTest.java |  22 ++
 10 files changed, 1496 insertions(+), 38 deletions(-)

diff --git a/processing/src/main/java/org/apache/druid/math/expr/ExprEval.java 
b/processing/src/main/java/org/apache/druid/math/expr/ExprEval.java
index 9c0f5e2736a..d74b623379c 100644
--- a/processing/src/main/java/org/apache/druid/math/expr/ExprEval.java
+++ b/processing/src/main/java/org/apache/druid/math/expr/ExprEval.java
@@ -666,7 +666,7 @@ public abstract class ExprEval<T>
     if (valueToCompare.isArray() && !typeToCompareWith.isArray()) {
       final Object[] array = valueToCompare.asArray();
       // cannot cast array to scalar if array length is greater than 1
-      if (array != null && array.length > 1) {
+      if (array != null && array.length != 1) {
         return null;
       }
     }
diff --git 
a/processing/src/main/java/org/apache/druid/query/filter/NullFilter.java 
b/processing/src/main/java/org/apache/druid/query/filter/NullFilter.java
index 168ca2bc0e6..cc2bdd2cf63 100644
--- a/processing/src/main/java/org/apache/druid/query/filter/NullFilter.java
+++ b/processing/src/main/java/org/apache/druid/query/filter/NullFilter.java
@@ -216,7 +216,7 @@ public class NullFilter extends 
AbstractOptimizableDimFilter implements Filter
                                          .build();
   }
 
-  private static class NullPredicateFactory implements DruidPredicateFactory
+  public static class NullPredicateFactory implements DruidPredicateFactory
   {
     public static final NullPredicateFactory INSTANCE = new 
NullPredicateFactory();
 
diff --git 
a/processing/src/main/java/org/apache/druid/query/filter/RangeFilter.java 
b/processing/src/main/java/org/apache/druid/query/filter/RangeFilter.java
index c34daa9156d..63fc48559ac 100644
--- a/processing/src/main/java/org/apache/druid/query/filter/RangeFilter.java
+++ b/processing/src/main/java/org/apache/druid/query/filter/RangeFilter.java
@@ -461,7 +461,11 @@ public class RangeFilter extends 
AbstractOptimizableDimFilter implements Filter
     final DimFilterToStringBuilder builder = new DimFilterToStringBuilder();
 
     if (lower != null) {
-      builder.append(lower);
+      if (matchValueType.isArray()) {
+        builder.append(Arrays.deepToString(lowerEval.asArray()));
+      } else {
+        builder.append(lower);
+      }
       if (lowerOpen) {
         builder.append(" < ");
       } else {
@@ -479,7 +483,11 @@ public class RangeFilter extends 
AbstractOptimizableDimFilter implements Filter
       } else {
         builder.append(" <= ");
       }
-      builder.append(upper);
+      if (matchValueType.isArray()) {
+        builder.append(Arrays.deepToString(upperEval.asArray()));
+      } else {
+        builder.append(upper);
+      }
     }
 
     return builder.appendFilterTuning(filterTuning).build();
diff --git 
a/processing/src/main/java/org/apache/druid/segment/nested/CompressedNestedDataComplexColumn.java
 
b/processing/src/main/java/org/apache/druid/segment/nested/CompressedNestedDataComplexColumn.java
index 7b0e99db5f3..cc259c3be0c 100644
--- 
a/processing/src/main/java/org/apache/druid/segment/nested/CompressedNestedDataComplexColumn.java
+++ 
b/processing/src/main/java/org/apache/druid/segment/nested/CompressedNestedDataComplexColumn.java
@@ -114,6 +114,7 @@ public abstract class 
CompressedNestedDataComplexColumn<TStringDictionary extend
   private final Supplier<TStringDictionary> stringDictionarySupplier;
   private final Supplier<FixedIndexed<Long>> longDictionarySupplier;
   private final Supplier<FixedIndexed<Double>> doubleDictionarySupplier;
+  @Nullable
   private final Supplier<FrontCodedIntArrayIndexed> arrayDictionarySupplier;
   private final SmooshedFileMapper fileMapper;
   private final String rootFieldPath;
@@ -1012,6 +1013,7 @@ public abstract class 
CompressedNestedDataComplexColumn<TStringDictionary extend
               stringDictionarySupplier,
               longDictionarySupplier,
               doubleDictionarySupplier,
+              arrayDictionarySupplier,
               arrayElementDictionarySupplier,
               arrayElementBitmaps,
               size
diff --git 
a/processing/src/main/java/org/apache/druid/segment/nested/NestedFieldColumnIndexSupplier.java
 
b/processing/src/main/java/org/apache/druid/segment/nested/NestedFieldColumnIndexSupplier.java
index abbd9184607..644e797e483 100644
--- 
a/processing/src/main/java/org/apache/druid/segment/nested/NestedFieldColumnIndexSupplier.java
+++ 
b/processing/src/main/java/org/apache/druid/segment/nested/NestedFieldColumnIndexSupplier.java
@@ -19,8 +19,10 @@
 
 package org.apache.druid.segment.nested;
 
+import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
 import com.google.common.collect.ImmutableList;
 import com.google.common.primitives.Doubles;
 import it.unimi.dsi.fastutil.doubles.DoubleArraySet;
@@ -39,7 +41,11 @@ import org.apache.druid.collections.bitmap.BitmapFactory;
 import org.apache.druid.collections.bitmap.ImmutableBitmap;
 import org.apache.druid.common.config.NullHandling;
 import org.apache.druid.common.guava.GuavaUtils;
+import org.apache.druid.error.DruidException;
 import org.apache.druid.java.util.common.StringUtils;
+import org.apache.druid.math.expr.ExprEval;
+import org.apache.druid.math.expr.ExprType;
+import org.apache.druid.math.expr.ExpressionType;
 import org.apache.druid.query.BitmapResultFactory;
 import org.apache.druid.query.filter.DruidDoublePredicate;
 import org.apache.druid.query.filter.DruidLongPredicate;
@@ -49,14 +55,19 @@ import org.apache.druid.segment.IntListUtils;
 import org.apache.druid.segment.column.ColumnConfig;
 import org.apache.druid.segment.column.ColumnIndexSupplier;
 import org.apache.druid.segment.column.ColumnType;
+import org.apache.druid.segment.column.TypeSignature;
+import org.apache.druid.segment.column.ValueType;
 import org.apache.druid.segment.data.FixedIndexed;
+import org.apache.druid.segment.data.FrontCodedIntArrayIndexed;
 import org.apache.druid.segment.data.GenericIndexed;
 import org.apache.druid.segment.data.Indexed;
+import org.apache.druid.segment.index.AllFalseBitmapColumnIndex;
 import org.apache.druid.segment.index.BitmapColumnIndex;
 import org.apache.druid.segment.index.SimpleBitmapColumnIndex;
 import 
org.apache.druid.segment.index.SimpleImmutableBitmapDelegatingIterableIndex;
 import org.apache.druid.segment.index.SimpleImmutableBitmapIndex;
 import org.apache.druid.segment.index.SimpleImmutableBitmapIterableIndex;
+import org.apache.druid.segment.index.semantic.ArrayElementIndexes;
 import 
org.apache.druid.segment.index.semantic.DictionaryEncodedStringValueIndex;
 import org.apache.druid.segment.index.semantic.DictionaryEncodedValueIndex;
 import org.apache.druid.segment.index.semantic.DruidPredicateIndexes;
@@ -64,7 +75,9 @@ import 
org.apache.druid.segment.index.semantic.LexicographicalRangeIndexes;
 import org.apache.druid.segment.index.semantic.NullValueIndex;
 import org.apache.druid.segment.index.semantic.NumericRangeIndexes;
 import org.apache.druid.segment.index.semantic.StringValueSetIndexes;
+import org.apache.druid.segment.index.semantic.ValueIndexes;
 
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.nio.ByteBuffer;
 import java.util.Iterator;
@@ -87,6 +100,8 @@ public class 
NestedFieldColumnIndexSupplier<TStringDictionary extends Indexed<By
   private final Supplier<FixedIndexed<Long>> globalLongDictionarySupplier;
   private final Supplier<FixedIndexed<Double>> globalDoubleDictionarySupplier;
 
+  private final Supplier<FrontCodedIntArrayIndexed> 
globalArrayDictionarySupplier;
+
   @SuppressWarnings({"FieldCanBeLocal", "unused"})
   @Nullable
   private final GenericIndexed<ImmutableBitmap> arrayElementBitmaps;
@@ -96,6 +111,7 @@ public class 
NestedFieldColumnIndexSupplier<TStringDictionary extends Indexed<By
 
   private final int adjustLongId;
   private final int adjustDoubleId;
+  private final int adjustArrayId;
   private final ColumnConfig columnConfig;
   private final int numRows;
 
@@ -108,6 +124,7 @@ public class 
NestedFieldColumnIndexSupplier<TStringDictionary extends Indexed<By
       Supplier<TStringDictionary> globalStringDictionarySupplier,
       Supplier<FixedIndexed<Long>> globalLongDictionarySupplier,
       Supplier<FixedIndexed<Double>> globalDoubleDictionarySupplier,
+      @Nullable Supplier<FrontCodedIntArrayIndexed> 
globalArrayDictionarySupplier,
       @Nullable Supplier<FixedIndexed<Integer>> arrayElementDictionarySupplier,
       @Nullable GenericIndexed<ImmutableBitmap> arrayElementBitmaps,
       int numRows
@@ -120,10 +137,12 @@ public class 
NestedFieldColumnIndexSupplier<TStringDictionary extends Indexed<By
     this.globalStringDictionarySupplier = globalStringDictionarySupplier;
     this.globalLongDictionarySupplier = globalLongDictionarySupplier;
     this.globalDoubleDictionarySupplier = globalDoubleDictionarySupplier;
+    this.globalArrayDictionarySupplier = globalArrayDictionarySupplier;
     this.arrayElementDictionarySupplier = arrayElementDictionarySupplier;
     this.arrayElementBitmaps = arrayElementBitmaps;
     this.adjustLongId = globalStringDictionarySupplier.get().size();
     this.adjustDoubleId = adjustLongId + 
globalLongDictionarySupplier.get().size();
+    this.adjustArrayId = adjustDoubleId + 
globalDoubleDictionarySupplier.get().size();
     this.columnConfig = columnConfig;
     this.numRows = numRows;
   }
@@ -157,7 +176,9 @@ public class 
NestedFieldColumnIndexSupplier<TStringDictionary extends Indexed<By
           }
           return null;
         case LONG:
-          if (clazz.equals(StringValueSetIndexes.class)) {
+          if (clazz.equals(ValueIndexes.class)) {
+            return (T) new NestedLongValueIndexes();
+          } else if (clazz.equals(StringValueSetIndexes.class)) {
             return (T) new NestedLongStringValueSetIndex();
           } else if (clazz.equals(NumericRangeIndexes.class)) {
             return (T) new NestedLongNumericRangeIndexes();
@@ -166,7 +187,9 @@ public class 
NestedFieldColumnIndexSupplier<TStringDictionary extends Indexed<By
           }
           return null;
         case DOUBLE:
-          if (clazz.equals(StringValueSetIndexes.class)) {
+          if (clazz.equals(ValueIndexes.class)) {
+            return (T) new NestedDoubleValueIndexes();
+          } else if (clazz.equals(StringValueSetIndexes.class)) {
             return (T) new NestedDoubleStringValueSetIndex();
           } else if (clazz.equals(NumericRangeIndexes.class)) {
             return (T) new NestedDoubleNumericRangeIndexes();
@@ -174,6 +197,13 @@ public class 
NestedFieldColumnIndexSupplier<TStringDictionary extends Indexed<By
             return (T) new NestedDoublePredicateIndexes();
           }
           return null;
+        case ARRAY:
+          if (clazz.equals(ValueIndexes.class)) {
+            return (T) new NestedArrayValueIndexes();
+          } else if (clazz.equals(ArrayElementIndexes.class)) {
+            return (T) new NestedArrayElementIndexes();
+          }
+          return null;
         default:
           return null;
       }
@@ -386,7 +416,7 @@ public class 
NestedFieldColumnIndexSupplier<TStringDictionary extends Indexed<By
             }
             return bitmapResultFactory.unionDimensionValueBitmaps(
                 ImmutableList.of(
-                    getBitmap(localDictionary.indexOf(globalId + 
adjustDoubleId)),
+                    getBitmap(localDictionary.indexOf(globalId)),
                     bitmaps.get(0)
                 )
             );
@@ -635,6 +665,56 @@ public class 
NestedFieldColumnIndexSupplier<TStringDictionary extends Indexed<By
     }
   }
 
+  private class NestedLongValueIndexes implements ValueIndexes
+  {
+    @Nullable
+    @Override
+    public BitmapColumnIndex forValue(@Nonnull Object value, 
TypeSignature<ValueType> valueType)
+    {
+      final ExprEval<?> eval = 
ExprEval.ofType(ExpressionType.fromColumnTypeStrict(valueType), value);
+      final ExprEval<?> castForComparison = 
ExprEval.castForEqualityComparison(eval, ExpressionType.LONG);
+      final ImmutableBitmap nullValueBitmap = 
localDictionarySupplier.get().get(0) == 0
+                                              ? bitmaps.get(0)
+                                              : 
bitmapFactory.makeEmptyImmutableBitmap();
+      if (castForComparison == null) {
+        return new AllFalseBitmapColumnIndex(bitmapFactory, nullValueBitmap);
+      }
+      final long longValue = castForComparison.asLong();
+
+
+      return new SimpleBitmapColumnIndex()
+      {
+        final FixedIndexed<Integer> localDictionary = 
localDictionarySupplier.get();
+        final FixedIndexed<Long> globalDictionary = 
globalLongDictionarySupplier.get();
+
+        @Override
+        public <T> T computeBitmapResult(BitmapResultFactory<T> 
bitmapResultFactory, boolean includeUnknown)
+        {
+          final int globalId = globalDictionary.indexOf(longValue);
+          if (globalId < 0) {
+            if (includeUnknown) {
+              return bitmapResultFactory.wrapDimensionValue(nullValueBitmap);
+            }
+            return 
bitmapResultFactory.wrapDimensionValue(bitmapFactory.makeEmptyImmutableBitmap());
+          }
+          final int id = localDictionary.indexOf(globalId + adjustLongId);
+          if (includeUnknown) {
+            if (id < 0) {
+              return bitmapResultFactory.wrapDimensionValue(nullValueBitmap);
+            }
+            return bitmapResultFactory.unionDimensionValueBitmaps(
+                ImmutableList.of(getBitmap(id), nullValueBitmap)
+            );
+          }
+          if (id < 0) {
+            return 
bitmapResultFactory.wrapDimensionValue(bitmapFactory.makeEmptyImmutableBitmap());
+          }
+          return bitmapResultFactory.wrapDimensionValue(getBitmap(id));
+        }
+      };
+    }
+  }
+
   private class NestedLongStringValueSetIndex implements StringValueSetIndexes
   {
     @Override
@@ -665,7 +745,7 @@ public class 
NestedFieldColumnIndexSupplier<TStringDictionary extends Indexed<By
             }
             return bitmapResultFactory.unionDimensionValueBitmaps(
                 ImmutableList.of(
-                    getBitmap(localDictionary.indexOf(globalId + 
adjustDoubleId)),
+                    getBitmap(localDictionary.indexOf(globalId + 
adjustLongId)),
                     bitmaps.get(0)
                 )
             );
@@ -870,6 +950,55 @@ public class 
NestedFieldColumnIndexSupplier<TStringDictionary extends Indexed<By
     }
   }
 
+  private class NestedDoubleValueIndexes implements ValueIndexes
+  {
+    @Nullable
+    @Override
+    public BitmapColumnIndex forValue(@Nonnull Object value, 
TypeSignature<ValueType> valueType)
+    {
+      final ExprEval<?> eval = 
ExprEval.ofType(ExpressionType.fromColumnTypeStrict(valueType), value);
+      final ExprEval<?> castForComparison = 
ExprEval.castForEqualityComparison(eval, ExpressionType.DOUBLE);
+      final ImmutableBitmap nullValueBitmap = 
localDictionarySupplier.get().get(0) == 0
+                                              ? bitmaps.get(0)
+                                              : 
bitmapFactory.makeEmptyImmutableBitmap();
+      if (castForComparison == null) {
+        return new AllFalseBitmapColumnIndex(bitmapFactory, nullValueBitmap);
+      }
+      final double doubleValue = castForComparison.asDouble();
+
+      return new SimpleBitmapColumnIndex()
+      {
+        final FixedIndexed<Integer> localDictionary = 
localDictionarySupplier.get();
+        final FixedIndexed<Double> globalDictionary = 
globalDoubleDictionarySupplier.get();
+
+        @Override
+        public <T> T computeBitmapResult(BitmapResultFactory<T> 
bitmapResultFactory, boolean includeUnknown)
+        {
+          final int globalId = globalDictionary.indexOf(doubleValue);
+          if (globalId < 0) {
+            if (includeUnknown) {
+              return bitmapResultFactory.wrapDimensionValue(nullValueBitmap);
+            }
+            return 
bitmapResultFactory.wrapDimensionValue(bitmapFactory.makeEmptyImmutableBitmap());
+          }
+          final int id = localDictionary.indexOf(globalId + adjustDoubleId);
+          if (includeUnknown) {
+            if (id < 0) {
+              return bitmapResultFactory.wrapDimensionValue(nullValueBitmap);
+            }
+            return bitmapResultFactory.unionDimensionValueBitmaps(
+                ImmutableList.of(getBitmap(id), nullValueBitmap)
+            );
+          }
+          if (id < 0) {
+            return 
bitmapResultFactory.wrapDimensionValue(bitmapFactory.makeEmptyImmutableBitmap());
+          }
+          return bitmapResultFactory.wrapDimensionValue(getBitmap(id));
+        }
+      };
+    }
+  }
+
   private class NestedDoubleStringValueSetIndex implements 
StringValueSetIndexes
   {
     @Override
@@ -1095,6 +1224,10 @@ public class 
NestedFieldColumnIndexSupplier<TStringDictionary extends Indexed<By
     final Indexed<ByteBuffer> stringDictionary = 
globalStringDictionarySupplier.get();
     final FixedIndexed<Long> longDictionary = 
globalLongDictionarySupplier.get();
     final FixedIndexed<Double> doubleDictionary = 
globalDoubleDictionarySupplier.get();
+    @Nullable
+    final FrontCodedIntArrayIndexed arrayDictionary = 
globalArrayDictionarySupplier == null
+                                                      ? null
+                                                      : 
globalArrayDictionarySupplier.get();
 
     IntList getIndexes(@Nullable String value)
     {
@@ -1260,6 +1393,10 @@ public class 
NestedFieldColumnIndexSupplier<TStringDictionary extends Indexed<By
             final DruidLongPredicate longPredicate = 
matcherFactory.makeLongPredicate();
             final DruidDoublePredicate doublePredicate = 
matcherFactory.makeDoublePredicate();
 
+            final Supplier<DruidObjectPredicate<Object[]>> 
arrayPredicateSupplier = Suppliers.memoize(
+                () -> matcherFactory.makeArrayPredicate(singleType)
+            );
+
             // in the future, this could use an int iterator
             final Iterator<Integer> iterator = localDictionary.iterator();
             int next;
@@ -1292,7 +1429,25 @@ public class 
NestedFieldColumnIndexSupplier<TStringDictionary extends Indexed<By
             {
               while (!nextSet && iterator.hasNext()) {
                 Integer nextValue = iterator.next();
-                if (nextValue >= adjustDoubleId) {
+                if (nextValue >= adjustArrayId) {
+                  // this shouldn't be possible since arrayIds will only exist 
if array dictionary is not null
+                  // v4 columns however have a null array dictionary
+                  Preconditions.checkNotNull(arrayDictionary);
+                  final int[] array = arrayDictionary.get(nextValue - 
adjustArrayId);
+                  final Object[] arrayObj = new Object[array.length];
+                  for (int i = 0; i < arrayObj.length; i++) {
+                    if (array[i] == 0) {
+                      arrayObj[i] = null;
+                    } else if (array[i] >= adjustDoubleId) {
+                      arrayObj[i] = doubleDictionary.get(array[i] - 
adjustDoubleId);
+                    } else if (array[i] >= adjustLongId) {
+                      arrayObj[i] = longDictionary.get(array[i] - 
adjustLongId);
+                    } else {
+                      arrayObj[i] = 
StringUtils.fromUtf8Nullable(stringDictionary.get(array[i]));
+                    }
+                  }
+                  nextSet = 
arrayPredicateSupplier.get().apply(arrayObj).matches(includeUnknown);
+                } else if (nextValue >= adjustDoubleId) {
                   nextSet = 
doublePredicate.applyDouble(doubleDictionary.get(nextValue - adjustDoubleId))
                                            .matches(includeUnknown);
                 } else if (nextValue >= adjustLongId) {
@@ -1313,4 +1468,187 @@ public class 
NestedFieldColumnIndexSupplier<TStringDictionary extends Indexed<By
       };
     }
   }
+
+  private class NestedArrayValueIndexes implements ValueIndexes
+  {
+    private final ImmutableBitmap nullValueBitmap = 
localDictionarySupplier.get().get(0) == 0
+                                                    ? bitmaps.get(0)
+                                                    : 
bitmapFactory.makeEmptyImmutableBitmap();
+
+    @Nullable
+    @Override
+    public BitmapColumnIndex forValue(@Nonnull Object value, 
TypeSignature<ValueType> valueType)
+    {
+      if (!valueType.isArray()) {
+        return new AllFalseBitmapColumnIndex(bitmapFactory, nullValueBitmap);
+      }
+      final ExprEval<?> eval = 
ExprEval.ofType(ExpressionType.fromColumnTypeStrict(valueType), value);
+      final ExprEval<?> castForComparison = ExprEval.castForEqualityComparison(
+          eval,
+          ExpressionType.fromColumnTypeStrict(singleType)
+      );
+      if (castForComparison == null) {
+        return new AllFalseBitmapColumnIndex(bitmapFactory, nullValueBitmap);
+      }
+      final Object[] arrayToMatch = castForComparison.asArray();
+      Indexed elements;
+      final int elementOffset;
+
+      switch (singleType.getElementType().getType()) {
+        case STRING:
+          elements = globalStringDictionarySupplier.get();
+          elementOffset = 0;
+          break;
+        case LONG:
+          elements = globalLongDictionarySupplier.get();
+          elementOffset = adjustLongId;
+          break;
+        case DOUBLE:
+          elements = globalDoubleDictionarySupplier.get();
+          elementOffset = adjustDoubleId;
+          break;
+        default:
+          throw DruidException.defensive(
+              "Unhandled array type [%s] how did this happen?",
+              singleType.getElementType()
+          );
+      }
+
+      final int[] ids = new int[arrayToMatch.length];
+      for (int i = 0; i < arrayToMatch.length; i++) {
+        if (arrayToMatch[i] == null) {
+          ids[i] = 0;
+        } else if (singleType.getElementType().is(ValueType.STRING)) {
+          ids[i] = elements.indexOf(StringUtils.toUtf8ByteBuffer((String) 
arrayToMatch[i]));
+        } else {
+          ids[i] = elements.indexOf(arrayToMatch[i]) + elementOffset;
+        }
+        if (ids[i] < 0) {
+          if (value == null) {
+            return new AllFalseBitmapColumnIndex(bitmapFactory, 
nullValueBitmap);
+          }
+        }
+      }
+
+      final FixedIndexed<Integer> localDictionary = 
localDictionarySupplier.get();
+      final FrontCodedIntArrayIndexed globalArrayDictionary = 
globalArrayDictionarySupplier.get();
+      return new SimpleBitmapColumnIndex()
+      {
+
+        @Override
+        public <T> T computeBitmapResult(BitmapResultFactory<T> 
bitmapResultFactory, boolean includeUnknown)
+        {
+          final int localId = 
localDictionary.indexOf(globalArrayDictionary.indexOf(ids) + adjustArrayId);
+          if (includeUnknown) {
+            if (localId < 0) {
+              return bitmapResultFactory.wrapDimensionValue(nullValueBitmap);
+            }
+            return bitmapResultFactory.unionDimensionValueBitmaps(
+                ImmutableList.of(getBitmap(localId), nullValueBitmap)
+            );
+          }
+          if (localId < 0) {
+            return 
bitmapResultFactory.wrapDimensionValue(bitmapFactory.makeEmptyImmutableBitmap());
+          }
+          return bitmapResultFactory.wrapDimensionValue(getBitmap(localId));
+        }
+      };
+    }
+  }
+
+  private class NestedArrayElementIndexes implements ArrayElementIndexes
+  {
+    private final ImmutableBitmap nullValueBitmap = 
localDictionarySupplier.get().get(0) == 0
+                                                    ? bitmaps.get(0)
+                                                    : 
bitmapFactory.makeEmptyImmutableBitmap();
+
+    @Nullable
+    @Override
+    public BitmapColumnIndex containsValue(@Nullable Object value, 
TypeSignature<ValueType> elementValueType)
+    {
+      // this column doesn't store nested arrays, bail out if checking if we 
contain an array
+      if (elementValueType.isArray()) {
+        return new AllFalseBitmapColumnIndex(bitmapFactory, nullValueBitmap);
+      }
+      final ExprEval<?> eval = 
ExprEval.ofType(ExpressionType.fromColumnTypeStrict(elementValueType), value);
+
+      final ExprEval<?> castForComparison = ExprEval.castForEqualityComparison(
+          eval,
+          ExpressionType.fromColumnTypeStrict(singleType.isArray() ? 
singleType.getElementType() : singleType)
+      );
+      if (castForComparison == null) {
+        return new AllFalseBitmapColumnIndex(bitmapFactory, nullValueBitmap);
+      }
+      final FixedIndexed<Integer> elementDictionary = 
arrayElementDictionarySupplier.get();
+      final Indexed globalElements;
+      final int elementOffset;
+      switch (singleType.getElementType().getType()) {
+        case STRING:
+          globalElements = globalStringDictionarySupplier.get();
+          elementOffset = 0;
+          break;
+        case LONG:
+          globalElements = globalLongDictionarySupplier.get();
+          elementOffset = adjustLongId;
+          break;
+        case DOUBLE:
+          globalElements = globalDoubleDictionarySupplier.get();
+          elementOffset = adjustDoubleId;
+          break;
+        default:
+          throw DruidException.defensive(
+              "Unhandled array type [%s] how did this happen?",
+              singleType.getElementType()
+          );
+      }
+
+      return new SimpleBitmapColumnIndex()
+      {
+
+        @Override
+        public <T> T computeBitmapResult(BitmapResultFactory<T> 
bitmapResultFactory, boolean includeUnknown)
+        {
+          final int elementId = getElementId();
+          if (includeUnknown) {
+            if (elementId < 0) {
+              return bitmapResultFactory.wrapDimensionValue(nullValueBitmap);
+            }
+            return bitmapResultFactory.unionDimensionValueBitmaps(
+                ImmutableList.of(getElementBitmap(elementId), nullValueBitmap)
+            );
+          }
+          if (elementId < 0) {
+            return 
bitmapResultFactory.wrapDimensionValue(bitmapFactory.makeEmptyImmutableBitmap());
+          }
+          return 
bitmapResultFactory.wrapDimensionValue(getElementBitmap(elementId));
+        }
+
+        private int getElementId()
+        {
+          if (castForComparison.value() == null) {
+            return 0;
+          }
+
+          if (castForComparison.type().is(ExprType.STRING)) {
+            return elementDictionary.indexOf(
+                
globalElements.indexOf(StringUtils.toUtf8ByteBuffer(castForComparison.asString()))
+            );
+          } else {
+            return elementDictionary.indexOf(
+                globalElements.indexOf(castForComparison.value()) + 
elementOffset
+            );
+          }
+        }
+
+        private ImmutableBitmap getElementBitmap(int idx)
+        {
+          if (idx < 0) {
+            return bitmapFactory.makeEmptyImmutableBitmap();
+          }
+          final ImmutableBitmap bitmap = arrayElementBitmaps.get(idx);
+          return bitmap == null ? bitmapFactory.makeEmptyImmutableBitmap() : 
bitmap;
+        }
+      };
+    }
+  }
 }
diff --git 
a/processing/src/test/java/org/apache/druid/segment/filter/ArrayContainsElementFilterTests.java
 
b/processing/src/test/java/org/apache/druid/segment/filter/ArrayContainsElementFilterTests.java
index 75f5dd60f58..434273870ff 100644
--- 
a/processing/src/test/java/org/apache/druid/segment/filter/ArrayContainsElementFilterTests.java
+++ 
b/processing/src/test/java/org/apache/druid/segment/filter/ArrayContainsElementFilterTests.java
@@ -75,8 +75,7 @@ public class ArrayContainsElementFilterTests
     @Test
     public void testArrayStringColumn()
     {
-      // only auto schema supports array columns... skip other segment types
-      Assume.assumeTrue(isAutoSchema());
+      Assume.assumeFalse(testName.contains("frame (columnar)") || 
testName.contains("rowBasedWithoutTypeSignature"));
         /*
             dim0 .. arrayString
             "0", .. ["a", "b", "c"]
@@ -160,8 +159,7 @@ public class ArrayContainsElementFilterTests
     @Test
     public void testArrayLongColumn()
     {
-      // only auto schema supports array columns... skip other segment types
-      Assume.assumeTrue(isAutoSchema());
+      Assume.assumeFalse(testName.contains("frame (columnar)") || 
testName.contains("rowBasedWithoutTypeSignature"));
         /*
             dim0 .. arrayLong
             "0", .. [1L, 2L, 3L]
@@ -241,8 +239,7 @@ public class ArrayContainsElementFilterTests
     @Test
     public void testArrayDoubleColumn()
     {
-      // only auto schema supports array columns... skip other segment types
-      Assume.assumeTrue(isAutoSchema());
+      Assume.assumeFalse(testName.contains("frame (columnar)") || 
testName.contains("rowBasedWithoutTypeSignature"));
         /*
             dim0 .. arrayDouble
             "0", .. [1.1, 2.2, 3.3]
@@ -300,8 +297,7 @@ public class ArrayContainsElementFilterTests
     @Test
     public void testArrayStringColumnContainsArrays()
     {
-      // only auto schema supports array columns... skip other segment types
-      Assume.assumeTrue(isAutoSchema());
+      Assume.assumeFalse(testName.contains("frame (columnar)") || 
testName.contains("rowBasedWithoutTypeSignature"));
       // these are not nested arrays, expect no matches
       assertFilterMatches(
           new ArrayContainsElementFilter(
@@ -330,9 +326,7 @@ public class ArrayContainsElementFilterTests
     @Test
     public void testArrayLongColumnContainsArrays()
     {
-      // only auto schema supports array columns... skip other segment types
-
-      Assume.assumeTrue(isAutoSchema());
+      Assume.assumeFalse(testName.contains("frame (columnar)") || 
testName.contains("rowBasedWithoutTypeSignature"));
 
       // these are not nested arrays, expect no matches
       assertFilterMatches(
@@ -362,8 +356,7 @@ public class ArrayContainsElementFilterTests
     @Test
     public void testArrayDoubleColumnContainsArrays()
     {
-      // only auto schema supports array columns... skip other segment types
-      Assume.assumeTrue(isAutoSchema());
+      Assume.assumeFalse(testName.contains("frame (columnar)") || 
testName.contains("rowBasedWithoutTypeSignature"));
       // these are not nested arrays, expect no matches
       assertFilterMatches(
           new ArrayContainsElementFilter(
@@ -472,7 +465,7 @@ public class ArrayContainsElementFilterTests
     public void testArrayContainsNestedArray()
     {
       // only auto schema supports array columns... skip other segment types
-      Assume.assumeTrue(isAutoSchema());
+      Assume.assumeFalse(testName.contains("frame (columnar)") || 
testName.contains("rowBasedWithoutTypeSignature"));
       assertFilterMatchesSkipVectorize(
           new ArrayContainsElementFilter("nestedArrayLong", 
ColumnType.LONG_ARRAY, new Object[]{1L, 2L, 3L}, null),
           ImmutableList.of("0", "2")
@@ -516,8 +509,404 @@ public class ArrayContainsElementFilterTests
             ImmutableList.of()
         );
       }
+    }
+
+    @Test
+    public void testNestedArrayStringColumn()
+    {
+      // duplicate of testArrayStringColumn but targeting nested.arrayString
+      Assume.assumeFalse(testName.contains("frame (columnar)") || 
testName.contains("rowBasedWithoutTypeSignature"));
+        /*
+            dim0 .. arrayString
+            "0", .. ["a", "b", "c"]
+            "1", .. []
+            "2", .. null
+            "3", .. ["a", "b", "c"]
+            "4", .. ["c", "d"]
+            "5", .. [null]
+         */
+
+      assertFilterMatches(
+          new ArrayContainsElementFilter(
+              "nested.arrayString",
+              ColumnType.STRING,
+              "a",
+              null
+          ),
+          ImmutableList.of("0", "3")
+      );
+      assertFilterMatches(
+          NotDimFilter.of(
+              new ArrayContainsElementFilter(
+                  "nested.arrayString",
+                  ColumnType.STRING,
+                  "a",
+                  null
+              )
+          ),
+          NullHandling.sqlCompatible()
+          ? ImmutableList.of("1", "4", "5")
+          : ImmutableList.of("1", "2", "4", "5")
+      );
+
+      assertFilterMatches(
+          new ArrayContainsElementFilter(
+              "nested.arrayString",
+              ColumnType.STRING,
+              "c",
+              null
+          ),
+          ImmutableList.of("0", "3", "4")
+      );
+      assertFilterMatches(
+          NotDimFilter.of(
+              new ArrayContainsElementFilter(
+                  "nested.arrayString",
+                  ColumnType.STRING,
+                  "c",
+                  null
+              )
+          ),
+          NullHandling.sqlCompatible()
+          ? ImmutableList.of("1", "5")
+          : ImmutableList.of("1", "2", "5")
+      );
+
+      assertFilterMatches(
+          new ArrayContainsElementFilter(
+              "nested.arrayString",
+              ColumnType.STRING,
+              null,
+              null
+          ),
+          ImmutableList.of("5")
+      );
+      assertFilterMatches(
+          NotDimFilter.of(
+              new ArrayContainsElementFilter(
+                  "nested.arrayString",
+                  ColumnType.STRING,
+                  null,
+                  null
+              )
+          ),
+          NullHandling.sqlCompatible()
+          ? ImmutableList.of("0", "1", "3", "4")
+          : ImmutableList.of("0", "1", "2", "3", "4")
+      );
+    }
+
+    @Test
+    public void testNestedArrayLongColumn()
+    {
+      // duplicate of testArrayLongColumn but targeting nested.arrayLong
+      Assume.assumeFalse(testName.contains("frame (columnar)") || 
testName.contains("rowBasedWithoutTypeSignature"));
+        /*
+            dim0 .. arrayLong
+            "0", .. [1L, 2L, 3L]
+            "1", .. []
+            "2", .. [1L, 2L, 3L]
+            "3", .. null
+            "4", .. [null]
+            "5", .. [123L, 345L]
+         */
+      assertFilterMatches(
+          new ArrayContainsElementFilter(
+              "nested.arrayLong",
+              ColumnType.LONG,
+              2L,
+              null
+          ),
+          ImmutableList.of("0", "2")
+      );
+      assertFilterMatches(
+          NotDimFilter.of(
+              new ArrayContainsElementFilter(
+                  "nested.arrayLong",
+                  ColumnType.LONG,
+                  2L,
+                  null
+              )
+          ),
+          NullHandling.sqlCompatible()
+          ? ImmutableList.of("1", "4", "5")
+          : ImmutableList.of("1", "3", "4", "5")
+      );
+
+      assertFilterMatches(
+          new ArrayContainsElementFilter(
+              "nested.arrayLong",
+              ColumnType.LONG,
+              null,
+              null
+          ),
+          ImmutableList.of("4")
+      );
+      assertFilterMatches(
+          NotDimFilter.of(
+              new ArrayContainsElementFilter(
+                  "nested.arrayLong",
+                  ColumnType.LONG,
+                  null,
+                  null
+              )
+          ),
+          NullHandling.sqlCompatible()
+          ? ImmutableList.of("0", "1", "2", "5")
+          : ImmutableList.of("0", "1", "2", "3", "5")
+      );
+
+      assertFilterMatches(
+          new ArrayContainsElementFilter(
+              "nested.arrayLong",
+              ColumnType.DOUBLE,
+              2.0,
+              null
+          ),
+          ImmutableList.of("0", "2")
+      );
+
+      assertFilterMatches(
+          new ArrayContainsElementFilter(
+              "nested.arrayLong",
+              ColumnType.STRING,
+              "2",
+              null
+          ),
+          ImmutableList.of("0", "2")
+      );
+    }
+
+    @Test
+    public void testNestedArrayDoubleColumn()
+    {
+      // duplicate of testArrayDoubleColumn but targeting nested.arrayDouble
+      Assume.assumeTrue(canTestArrayColumns());
+        /*
+            dim0 .. arrayDouble
+            "0", .. [1.1, 2.2, 3.3]
+            "1", .. [1.1, 2.2, 3.3]
+            "2", .. [null]
+            "3", .. []
+            "4", .. [-1.1, -333.3]
+            "5", .. null
+         */
+
+      assertFilterMatches(
+          new ArrayContainsElementFilter(
+              "nested.arrayDouble",
+              ColumnType.DOUBLE,
+              2.2,
+              null
+          ),
+          ImmutableList.of("0", "1")
+      );
+      assertFilterMatches(
+          NotDimFilter.of(
+              new ArrayContainsElementFilter(
+                  "nested.arrayDouble",
+                  ColumnType.DOUBLE,
+                  2.2,
+                  null
+              )
+          ),
+          NullHandling.sqlCompatible()
+          ? ImmutableList.of("2", "3", "4")
+          : ImmutableList.of("2", "3", "4", "5")
+      );
+
+      assertFilterMatches(
+          new ArrayContainsElementFilter(
+              "nested.arrayDouble",
+              ColumnType.STRING,
+              "2.2",
+              null
+          ),
+          ImmutableList.of("0", "1")
+      );
+
+      assertFilterMatches(
+          new ArrayContainsElementFilter(
+              "nested.arrayDouble",
+              ColumnType.DOUBLE,
+              null,
+              null
+          ),
+          ImmutableList.of("2")
+      );
+    }
+
+    @Test
+    public void testNestedArrayStringColumnContainsArrays()
+    {
+      // duplicate of testArrayStringColumnContainsArrays but targeting 
nested.arrayString
+      Assume.assumeTrue(canTestArrayColumns());
+      // these are not nested arrays, expect no matches
+      assertFilterMatches(
+          new ArrayContainsElementFilter(
+              "nested.arrayString",
+              ColumnType.STRING_ARRAY,
+              ImmutableList.of("a", "b", "c"),
+              null
+          ),
+          ImmutableList.of()
+      );
+      assertFilterMatches(
+          NotDimFilter.of(
+              new ArrayContainsElementFilter(
+                  "nested.arrayString",
+                  ColumnType.STRING_ARRAY,
+                  ImmutableList.of("a", "b", "c"),
+                  null
+              )
+          ),
+          NullHandling.sqlCompatible()
+          ? ImmutableList.of("0", "1", "3", "4", "5")
+          : ImmutableList.of("0", "1", "2", "3", "4", "5")
+      );
+    }
 
+    @Test
+    public void testNestedArrayLongColumnContainsArrays()
+    {
+      // duplicate of testArrayLongColumnContainsArrays but targeting 
nested.arrayLong
+      Assume.assumeTrue(canTestArrayColumns());
 
+      // these are not nested arrays, expect no matches
+      assertFilterMatches(
+          new ArrayContainsElementFilter(
+              "nested.arrayLong",
+              ColumnType.LONG_ARRAY,
+              ImmutableList.of(1L, 2L, 3L),
+              null
+          ),
+          ImmutableList.of()
+      );
+      assertFilterMatches(
+          NotDimFilter.of(
+              new ArrayContainsElementFilter(
+                  "nested.arrayLong",
+                  ColumnType.LONG_ARRAY,
+                  ImmutableList.of(1L, 2L, 3L),
+                  null
+              )
+          ),
+          NullHandling.sqlCompatible()
+          ? ImmutableList.of("0", "1", "2", "4", "5")
+          : ImmutableList.of("0", "1", "2", "3", "4", "5")
+      );
+    }
+
+    @Test
+    public void testNestedArrayDoubleColumnContainsArrays()
+    {
+      // duplicate of testArrayDoubleColumnContainsArrays but targeting 
nested.arrayDouble
+      Assume.assumeTrue(canTestArrayColumns());
+      // these are not nested arrays, expect no matches
+      assertFilterMatches(
+          new ArrayContainsElementFilter(
+              "nested.arrayDouble",
+              ColumnType.DOUBLE_ARRAY,
+              ImmutableList.of(1.1, 2.2, 3.3),
+              null
+          ),
+          ImmutableList.of()
+      );
+      assertFilterMatches(
+          NotDimFilter.of(
+              new ArrayContainsElementFilter(
+                  "nested.arrayDouble",
+                  ColumnType.DOUBLE_ARRAY,
+                  ImmutableList.of(1.1, 2.2, 3.3),
+                  null
+              )
+          ),
+          NullHandling.sqlCompatible()
+          ? ImmutableList.of("0", "1", "2", "3", "4")
+          : ImmutableList.of("0", "1", "2", "3", "4", "5")
+      );
+    }
+
+    @Test
+    public void testNestedScalarColumnContains()
+    {
+      Assume.assumeTrue(canTestArrayColumns());
+
+      // duplicate of testScalarColumnContains but targeting nested columns
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.s0", ColumnType.STRING, "a", 
null),
+          ImmutableList.of("1", "5")
+      );
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.s0", ColumnType.STRING, "b", 
null),
+          ImmutableList.of("2")
+      );
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.s0", ColumnType.STRING, "c", 
null),
+          ImmutableList.of("4")
+      );
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.s0", ColumnType.STRING, 
"noexist", null),
+          ImmutableList.of()
+      );
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.s0", ColumnType.STRING_ARRAY, 
ImmutableList.of("c"), null),
+          ImmutableList.of("4")
+      );
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.s0", ColumnType.STRING_ARRAY, 
ImmutableList.of("a", "c"), null),
+          ImmutableList.of()
+      );
+
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.d0", ColumnType.DOUBLE, 10.1, 
null),
+          ImmutableList.of("1")
+      );
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.d0", ColumnType.DOUBLE, 
120.0245, null),
+          ImmutableList.of("3")
+      );
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.d0", ColumnType.DOUBLE, 
765.432, null),
+          ImmutableList.of("5")
+      );
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.d0", ColumnType.DOUBLE, 
765.431, null),
+          ImmutableList.of()
+      );
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.d0", ColumnType.DOUBLE_ARRAY, 
new Object[]{10.1}, null),
+          ImmutableList.of("1")
+      );
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.d0", ColumnType.DOUBLE_ARRAY, 
new Object[]{10.1, 120.0245}, null),
+          ImmutableList.of()
+      );
+
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.l0", ColumnType.LONG, 100L, 
null),
+          ImmutableList.of("1")
+      );
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.l0", ColumnType.LONG, 40L, 
null),
+          ImmutableList.of("2")
+      );
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.l0", ColumnType.LONG, 9001L, 
null),
+          ImmutableList.of("4")
+      );
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.l0", ColumnType.LONG, 9000L, 
null),
+          ImmutableList.of()
+      );
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.l0", ColumnType.LONG_ARRAY, 
ImmutableList.of(9001L), null),
+          ImmutableList.of("4")
+      );
+      assertFilterMatches(
+          new ArrayContainsElementFilter("nested.l0", ColumnType.LONG_ARRAY, 
ImmutableList.of(40L, 9001L), null),
+          ImmutableList.of()
+      );
     }
   }
 
diff --git 
a/processing/src/test/java/org/apache/druid/segment/filter/BaseFilterTest.java 
b/processing/src/test/java/org/apache/druid/segment/filter/BaseFilterTest.java
index 1106801729b..f4ecad4485b 100644
--- 
a/processing/src/test/java/org/apache/druid/segment/filter/BaseFilterTest.java
+++ 
b/processing/src/test/java/org/apache/druid/segment/filter/BaseFilterTest.java
@@ -41,6 +41,7 @@ import org.apache.druid.data.input.impl.TimestampSpec;
 import org.apache.druid.frame.FrameType;
 import org.apache.druid.frame.segment.FrameSegment;
 import org.apache.druid.frame.segment.FrameStorageAdapter;
+import org.apache.druid.guice.NestedDataModule;
 import org.apache.druid.java.util.common.DateTimes;
 import org.apache.druid.java.util.common.ISE;
 import org.apache.druid.java.util.common.Intervals;
@@ -78,6 +79,7 @@ import org.apache.druid.segment.RowAdapters;
 import org.apache.druid.segment.RowBasedColumnSelectorFactory;
 import org.apache.druid.segment.RowBasedStorageAdapter;
 import org.apache.druid.segment.StorageAdapter;
+import org.apache.druid.segment.TestHelper;
 import org.apache.druid.segment.VirtualColumns;
 import org.apache.druid.segment.column.ColumnType;
 import org.apache.druid.segment.column.RowSignature;
@@ -99,6 +101,7 @@ import org.apache.druid.segment.vector.VectorObjectSelector;
 import org.apache.druid.segment.vector.VectorValueSelector;
 import org.apache.druid.segment.virtual.ExpressionVirtualColumn;
 import org.apache.druid.segment.virtual.ListFilteredVirtualColumn;
+import org.apache.druid.segment.virtual.NestedFieldVirtualColumn;
 import 
org.apache.druid.segment.writeout.OffHeapMemorySegmentWriteOutMediumFactory;
 import org.apache.druid.segment.writeout.SegmentWriteOutMediumFactory;
 import org.apache.druid.segment.writeout.TmpFileSegmentWriteOutMediumFactory;
@@ -152,7 +155,13 @@ public abstract class BaseFilterTest extends 
InitializedNullHandlingTest
           new ListFilteredVirtualColumn("allow-dim0", 
DefaultDimensionSpec.of("dim0"), ImmutableSet.of("3", "4"), true),
           new ListFilteredVirtualColumn("deny-dim0", 
DefaultDimensionSpec.of("dim0"), ImmutableSet.of("3", "4"), false),
           new ListFilteredVirtualColumn("allow-dim2", 
DefaultDimensionSpec.of("dim2"), ImmutableSet.of("a"), true),
-          new ListFilteredVirtualColumn("deny-dim2", 
DefaultDimensionSpec.of("dim2"), ImmutableSet.of("a"), false)
+          new ListFilteredVirtualColumn("deny-dim2", 
DefaultDimensionSpec.of("dim2"), ImmutableSet.of("a"), false),
+          new NestedFieldVirtualColumn("nested", "$.s0", "nested.s0", 
ColumnType.STRING),
+          new NestedFieldVirtualColumn("nested", "$.d0", "nested.d0", 
ColumnType.DOUBLE),
+          new NestedFieldVirtualColumn("nested", "$.l0", "nested.l0", 
ColumnType.LONG),
+          new NestedFieldVirtualColumn("nested", "$.arrayLong", 
"nested.arrayLong", ColumnType.LONG_ARRAY),
+          new NestedFieldVirtualColumn("nested", "$.arrayDouble", 
"nested.arrayDouble", ColumnType.DOUBLE_ARRAY),
+          new NestedFieldVirtualColumn("nested", "$.arrayString", 
"nested.arrayString", ColumnType.STRING_ARRAY)
       )
   );
 
@@ -178,6 +187,7 @@ public abstract class BaseFilterTest extends 
InitializedNullHandlingTest
                    .add(new AutoTypeColumnSchema("arrayLong", 
ColumnType.LONG_ARRAY))
                    .add(new AutoTypeColumnSchema("arrayDouble", 
ColumnType.DOUBLE_ARRAY))
                    .add(new AutoTypeColumnSchema("variant", null))
+                   .add(new AutoTypeColumnSchema("nested", null))
                    .build()
   );
 
@@ -203,6 +213,7 @@ public abstract class BaseFilterTest extends 
InitializedNullHandlingTest
                   .add("arrayLong", ColumnType.LONG_ARRAY)
                   .add("arrayDouble", ColumnType.DOUBLE_ARRAY)
                   .add("variant", ColumnType.STRING_ARRAY)
+                  .add("nested", ColumnType.NESTED_DATA)
                   .build();
 
   static final List<InputRow> DEFAULT_ROWS = ImmutableList.of(
@@ -218,7 +229,17 @@ public abstract class BaseFilterTest extends 
InitializedNullHandlingTest
           ImmutableList.of("a", "b", "c"),
           ImmutableList.of(1L, 2L, 3L),
           ImmutableList.of(1.1, 2.2, 3.3),
-          "abc"
+          "abc",
+          TestHelper.makeMapWithExplicitNull(
+              "s0", "",
+              "d0", 0.0,
+              "f0", 0.0f,
+              "l0", 0L,
+              "arrayString", ImmutableList.of("a", "b", "c"),
+              "arrayLong", ImmutableList.of(1L, 2L, 3L),
+              "arrayDouble", ImmutableList.of(1.1, 2.2, 3.3),
+              "variant", "abc"
+          )
       ),
       makeDefaultSchemaRow(
           "1",
@@ -232,7 +253,17 @@ public abstract class BaseFilterTest extends 
InitializedNullHandlingTest
           ImmutableList.of(),
           ImmutableList.of(),
           new Object[]{1.1, 2.2, 3.3},
-          100L
+          100L,
+          TestHelper.makeMapWithExplicitNull(
+              "s0", "a",
+              "d0", 10.1,
+              "f0", 10.1f,
+              "l0", 100L,
+              "arrayString", ImmutableList.of(),
+              "arrayLong", ImmutableList.of(),
+              "arrayDouble", new Object[]{1.1, 2.2, 3.3},
+              "variant", 100L
+          )
       ),
       makeDefaultSchemaRow(
           "2",
@@ -246,7 +277,17 @@ public abstract class BaseFilterTest extends 
InitializedNullHandlingTest
           null,
           new Object[]{1L, 2L, 3L},
           Collections.singletonList(null),
-          "100"
+          "100",
+          TestHelper.makeMapWithExplicitNull(
+              "s0", "b",
+              "d0", null,
+              "f0", 5.5f,
+              "l0", 40L,
+              "arrayString", null,
+              "arrayLong", new Object[]{1L, 2L, 3L},
+              "arrayDouble", Collections.singletonList(null),
+              "variant", "100"
+          )
       ),
       makeDefaultSchemaRow(
           "3",
@@ -260,7 +301,17 @@ public abstract class BaseFilterTest extends 
InitializedNullHandlingTest
           new Object[]{"a", "b", "c"},
           null,
           ImmutableList.of(),
-          Arrays.asList(1.1, 2.2, 3.3)
+          Arrays.asList(1.1, 2.2, 3.3),
+          TestHelper.makeMapWithExplicitNull(
+              "s0", null,
+              "d0", 120.0245,
+              "f0", 110.0f,
+              "l0", null,
+              "arrayString", new Object[]{"a", "b", "c"},
+              "arrayLong", null,
+              "arrayDouble", ImmutableList.of(),
+              "variant", Arrays.asList(1.1, 2.2, 3.3)
+          )
       ),
       makeDefaultSchemaRow(
           "4",
@@ -274,7 +325,17 @@ public abstract class BaseFilterTest extends 
InitializedNullHandlingTest
           ImmutableList.of("c", "d"),
           Collections.singletonList(null),
           new Object[]{-1.1, -333.3},
-          12.34
+          12.34,
+          TestHelper.makeMapWithExplicitNull(
+              "s0", "c",
+              "d0", 60.0,
+              "f0", null,
+              "l0", 9001L,
+              "arrayString", ImmutableList.of("c", "d"),
+              "arrayLong", Collections.singletonList(null),
+              "arrayDouble", new Object[]{-1.1, -333.3},
+              "variant", 12.34
+          )
       ),
       makeDefaultSchemaRow(
           "5",
@@ -288,7 +349,17 @@ public abstract class BaseFilterTest extends 
InitializedNullHandlingTest
           Collections.singletonList(null),
           new Object[]{123L, 345L},
           null,
-          Arrays.asList(100, 200, 300)
+          Arrays.asList(100, 200, 300),
+          TestHelper.makeMapWithExplicitNull(
+              "s0", "a",
+              "d0", 765.432,
+              "f0", 123.45f,
+              "l0", 12345L,
+              "arrayString", Collections.singletonList(null),
+              "arrayLong", new Object[]{123L, 345L},
+              "arrayDouble", null,
+              "variant", Arrays.asList(100, 200, 300)
+          )
       )
   );
 
@@ -372,6 +443,7 @@ public abstract class BaseFilterTest extends 
InitializedNullHandlingTest
   @Before
   public void setUp() throws Exception
   {
+    NestedDataModule.registerHandlersAndSerde();
     String className = getClass().getName();
     Map<String, Pair<StorageAdapter, Closeable>> adaptersForClass = 
adapterCache.get().get(className);
     if (adaptersForClass == null) {
@@ -572,7 +644,7 @@ public abstract class BaseFilterTest extends 
InitializedNullHandlingTest
                         input -> 
Pair.of(input.buildRowBasedSegmentWithTypeSignature().asStorageAdapter(), () -> 
{})
                     )
                     .put("frame (row-based)", input -> {
-                      // remove array type columns from frames since they 
aren't currently supported other than string
+                      // remove variant type columns from row frames since 
they aren't currently supported
                       input.mapSchema(
                           schema ->
                               new IncrementalIndexSchema(
@@ -584,7 +656,7 @@ public abstract class BaseFilterTest extends 
InitializedNullHandlingTest
                                       schema.getDimensionsSpec()
                                             .getDimensions()
                                             .stream()
-                                            .filter(dimensionSchema -> 
!(dimensionSchema instanceof AutoTypeColumnSchema))
+                                            .filter(dimensionSchema -> 
!dimensionSchema.getName().equals("variant"))
                                             .collect(Collectors.toList())
                                   ),
                                   schema.getMetrics(),
@@ -595,7 +667,7 @@ public abstract class BaseFilterTest extends 
InitializedNullHandlingTest
                       return Pair.of(segment.asStorageAdapter(), segment);
                     })
                     .put("frame (columnar)", input -> {
-                      // remove array type columns from frames since they 
aren't currently supported other than string
+                      // remove array type columns from columnar frames since 
they aren't currently supported
                       input.mapSchema(
                           schema ->
                               new IncrementalIndexSchema(
@@ -674,6 +746,14 @@ public abstract class BaseFilterTest extends 
InitializedNullHandlingTest
     return false;
   }
 
+  protected boolean canTestArrayColumns()
+  {
+    if (testName.contains("frame (columnar)") || 
testName.contains("rowBasedWithoutTypeSignature")) {
+      return false;
+    }
+    return true;
+  }
+
   private Filter makeFilter(final DimFilter dimFilter)
   {
     if (dimFilter == null) {
diff --git 
a/processing/src/test/java/org/apache/druid/segment/filter/EqualityFilterTests.java
 
b/processing/src/test/java/org/apache/druid/segment/filter/EqualityFilterTests.java
index 6521d5cf957..9c2bd90071c 100644
--- 
a/processing/src/test/java/org/apache/druid/segment/filter/EqualityFilterTests.java
+++ 
b/processing/src/test/java/org/apache/druid/segment/filter/EqualityFilterTests.java
@@ -773,7 +773,7 @@ public class EqualityFilterTests
     @Test
     public void testNumeric()
     {
-    /*
+      /*
         dim0   d0         f0        l0
         "0" .. 0.0,       0.0f,     0L
         "1" .. 10.1,      10.1f,    100L
@@ -839,8 +839,7 @@ public class EqualityFilterTests
     @Test
     public void testArrays()
     {
-      // only auto schema supports array columns... skip other segment types
-      Assume.assumeTrue(isAutoSchema());
+      Assume.assumeTrue(canTestArrayColumns());
       /*
           dim0 .. arrayString               arrayLong             arrayDouble
           "0", .. ["a", "b", "c"],          [1L, 2L, 3L],         [1.1, 2.2, 
3.3]
@@ -1112,6 +1111,7 @@ public class EqualityFilterTests
       "5", .. [100, 200, 300]
 
        */
+      // only auto well supports variant types
       Assume.assumeTrue(isAutoSchema());
       assertFilterMatches(
           new EqualityFilter(
@@ -1202,6 +1202,414 @@ public class EqualityFilterTests
           ImmutableList.of("5")
       );
     }
+
+    @Test
+    public void testNestedColumnEquality()
+    {
+      // nested column mirrors the top level columns, so these cases are 
copied from other tests
+      Assume.assumeTrue(canTestArrayColumns());
+
+      if (NullHandling.sqlCompatible()) {
+        assertFilterMatches(
+            new EqualityFilter("nested.s0", ColumnType.STRING, "", null),
+            ImmutableList.of("0")
+        );
+        assertFilterMatches(
+            NotDimFilter.of(new EqualityFilter("nested.s0", ColumnType.STRING, 
"", null)),
+            ImmutableList.of("1", "2", "4", "5")
+        );
+      }
+      assertFilterMatches(new EqualityFilter("nested.s0", ColumnType.STRING, 
"a", null), ImmutableList.of("1", "5"));
+      assertFilterMatches(new EqualityFilter("nested.s0", ColumnType.STRING, 
"b", null), ImmutableList.of("2"));
+      assertFilterMatches(new EqualityFilter("nested.s0", ColumnType.STRING, 
"c", null), ImmutableList.of("4"));
+      assertFilterMatches(new EqualityFilter("nested.s0", ColumnType.STRING, 
"noexist", null), ImmutableList.of());
+
+      if (NullHandling.sqlCompatible()) {
+        assertFilterMatches(
+            NotDimFilter.of(new EqualityFilter("nested.s0", ColumnType.STRING, 
"a", null)),
+            ImmutableList.of("0", "2", "4")
+        );
+        // "(s0 = 'a') is not true", same rows as "s0 <> 'a'", but also with 
null rows
+        assertFilterMatches(
+            NotDimFilter.of(IsTrueDimFilter.of(new EqualityFilter("nested.s0", 
ColumnType.STRING, "a", null))),
+            ImmutableList.of("0", "2", "3", "4")
+        );
+        // "(s0 = 'a') is true", equivalent to "s0 = 'a'"
+        assertFilterMatches(
+            IsTrueDimFilter.of(new EqualityFilter("nested.s0", 
ColumnType.STRING, "a", null)),
+            ImmutableList.of("1", "5")
+        );
+        // "(s0 = 'a') is false", equivalent results to "s0 <> 'a'"
+        assertFilterMatches(
+            IsFalseDimFilter.of(new EqualityFilter("nested.s0", 
ColumnType.STRING, "a", null)),
+            ImmutableList.of("0", "2", "4")
+        );
+        // "(s0 = 'a') is not false", same rows as "s0 = 'a'", but also with 
null rows
+        assertFilterMatches(
+            NotDimFilter.of(IsFalseDimFilter.of(new 
EqualityFilter("nested.s0", ColumnType.STRING, "a", null))),
+            ImmutableList.of("1", "3", "5")
+        );
+
+        try {
+          // make sure if 3vl is disabled with behave with 2vl
+          NullHandling.initializeForTestsWithValues(false, false, null);
+          assertFilterMatches(
+              NotDimFilter.of(new EqualityFilter("nested.s0", 
ColumnType.STRING, "a", null)),
+              ImmutableList.of("0", "2", "3", "4")
+          );
+        }
+        finally {
+          NullHandling.initializeForTests();
+        }
+        assertFilterMatches(
+            NotDimFilter.of(new EqualityFilter("nested.s0", ColumnType.STRING, 
"noexist", null)),
+            ImmutableList.of("0", "1", "2", "4", "5")
+        );
+      } else {
+        assertFilterMatches(
+            NotDimFilter.of(new EqualityFilter("nested.s0", ColumnType.STRING, 
"a", null)),
+            ImmutableList.of("0", "2", "3", "4")
+        );
+        assertFilterMatches(
+            NotDimFilter.of(new EqualityFilter("nested.s0", ColumnType.STRING, 
"noexist", null)),
+            ImmutableList.of("0", "1", "2", "3", "4", "5")
+        );
+
+        // in default value mode, is true/is false are basically pointless 
since they have the same behavior as = and <>
+        // "(s0 = 'a') is not true" equivalent to "s0 <> 'a'"
+        assertFilterMatches(
+            NotDimFilter.of(IsTrueDimFilter.of(new EqualityFilter("nested.s0", 
ColumnType.STRING, "a", null))),
+            ImmutableList.of("0", "2", "3", "4")
+        );
+        // "(s0 = 'a') is true", equivalent to "s0 = 'a'"
+        assertFilterMatches(
+            IsTrueDimFilter.of(new EqualityFilter("nested.s0", 
ColumnType.STRING, "a", null)),
+            ImmutableList.of("1", "5")
+        );
+        // "(s0 = 'a') is false" equivalent to "s0 <> 'a'"
+        assertFilterMatches(
+            IsFalseDimFilter.of(new EqualityFilter("nested.s0", 
ColumnType.STRING, "a", null)),
+            ImmutableList.of("0", "2", "3", "4")
+        );
+        // "(s0 = 'a') is not false", equivalent to "s0 = 'a'"
+        assertFilterMatches(
+            NotDimFilter.of(IsFalseDimFilter.of(new 
EqualityFilter("nested.s0", ColumnType.STRING, "a", null))),
+            ImmutableList.of("1", "5")
+        );
+      }
+
+      /*
+        dim0   d0         l0
+        "0" .. 0.0,       0L
+        "1" .. 10.1,      100L
+        "2" .. null,      40L
+        "3" .. 120.0245,  null
+        "4" .. 60.0,      9001L
+        "5" .. 765.432,   12345L
+     */
+
+      // nested columns do not coerce null to default values
+
+      assertFilterMatches(new EqualityFilter("nested.d0", ColumnType.DOUBLE, 
0.0, null), ImmutableList.of("0"));
+      assertFilterMatches(
+          NotDimFilter.of(new EqualityFilter("nested.d0", ColumnType.DOUBLE, 
0.0, null)),
+          NullHandling.sqlCompatible()
+          ? ImmutableList.of("1", "3", "4", "5")
+          : ImmutableList.of("1", "2", "3", "4", "5")
+      );
+      assertFilterMatches(new EqualityFilter("nested.l0", ColumnType.LONG, 0L, 
null), ImmutableList.of("0"));
+      assertFilterMatches(
+          NotDimFilter.of(new EqualityFilter("nested.l0", ColumnType.LONG, 0L, 
null)),
+          NullHandling.sqlCompatible()
+          ? ImmutableList.of("1", "2", "4", "5")
+          : ImmutableList.of("1", "2", "3", "4", "5")
+      );
+
+      assertFilterMatches(new EqualityFilter("nested.l0", ColumnType.STRING, 
"0", null), ImmutableList.of("0"));
+      assertFilterMatches(new EqualityFilter("nested.l0", ColumnType.STRING, 
"0", null), ImmutableList.of("0"));
+
+      assertFilterMatches(new EqualityFilter("nested.d0", ColumnType.DOUBLE, 
10.1, null), ImmutableList.of("1"));
+      assertFilterMatches(new EqualityFilter("nested.d0", ColumnType.DOUBLE, 
120.0245, null), ImmutableList.of("3"));
+      assertFilterMatches(new EqualityFilter("nested.d0", ColumnType.DOUBLE, 
765.432, null), ImmutableList.of("5"));
+      assertFilterMatches(new EqualityFilter("nested.d0", ColumnType.DOUBLE, 
765.431, null), ImmutableList.of());
+
+      // different type matcher
+      assertFilterMatches(
+          new EqualityFilter("nested.d0", ColumnType.LONG, 0L, null),
+          ImmutableList.of("0")
+      );
+      assertFilterMatches(new EqualityFilter("d0", ColumnType.LONG, 60L, 
null), ImmutableList.of("4"));
+
+      assertFilterMatches(new EqualityFilter("nested.l0", ColumnType.LONG, 
100L, null), ImmutableList.of("1"));
+      assertFilterMatches(new EqualityFilter("nested.l0", ColumnType.LONG, 
40L, null), ImmutableList.of("2"));
+      assertFilterMatches(new EqualityFilter("nested.l0", ColumnType.LONG, 
9001L, null), ImmutableList.of("4"));
+      assertFilterMatches(new EqualityFilter("nested.l0", ColumnType.LONG, 
9000L, null), ImmutableList.of());
+
+      // test loss of precision
+      assertFilterMatches(new EqualityFilter("nested.l0", ColumnType.DOUBLE, 
100.1, null), ImmutableList.of());
+      assertFilterMatches(new EqualityFilter("nested.l0", ColumnType.DOUBLE, 
100.0, null), ImmutableList.of("1"));
+      assertFilterMatches(new EqualityFilter("nested.l0", ColumnType.DOUBLE, 
40.1, null), ImmutableList.of());
+      assertFilterMatches(new EqualityFilter("nested.l0", ColumnType.DOUBLE, 
40.0, null), ImmutableList.of("2"));
+      assertFilterMatches(new EqualityFilter("nested.l0", ColumnType.DOUBLE, 
9001.1, null), ImmutableList.of());
+      assertFilterMatches(new EqualityFilter("nested.l0", ColumnType.DOUBLE, 
9001.0, null), ImmutableList.of("4"));
+
+      /*
+          dim0 .. arrayString               arrayLong             arrayDouble
+          "0", .. ["a", "b", "c"],          [1L, 2L, 3L],         [1.1, 2.2, 
3.3]
+          "1", .. [],                       [],                   [1.1, 2.2, 
3.3]
+          "2", .. null,                     [1L, 2L, 3L],         [null]
+          "3", .. ["a", "b", "c"],          null,                 []
+          "4", .. ["c", "d"],               [null],               [-1.1, 
-333.3]
+          "5", .. [null],                   [123L, 345L],         null
+       */
+
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayString",
+              ColumnType.STRING_ARRAY,
+              ImmutableList.of("a", "b", "c"),
+              null
+          ),
+          ImmutableList.of("0", "3")
+      );
+      assertFilterMatches(
+          NotDimFilter.of(
+              new EqualityFilter(
+                  "nested.arrayString",
+                  ColumnType.STRING_ARRAY,
+                  ImmutableList.of("a", "b", "c"),
+                  null
+              )
+          ),
+          NullHandling.sqlCompatible()
+          ? ImmutableList.of("1", "4", "5")
+          : ImmutableList.of("1", "2", "4", "5")
+      );
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayString",
+              ColumnType.STRING_ARRAY,
+              new Object[]{"a", "b", "c"},
+              null
+          ),
+          ImmutableList.of("0", "3")
+      );
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayString",
+              ColumnType.STRING_ARRAY,
+              ImmutableList.of(),
+              null
+          ),
+          ImmutableList.of("1")
+      );
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayString",
+              ColumnType.STRING_ARRAY,
+              new Object[]{null},
+              null
+          ),
+          ImmutableList.of("5")
+      );
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayString",
+              ColumnType.STRING_ARRAY,
+              new Object[]{null, null},
+              null
+          ),
+          ImmutableList.of()
+      );
+      assertFilterMatches(
+          NotDimFilter.of(
+              new EqualityFilter(
+                  "nested.arrayString",
+                  ColumnType.STRING_ARRAY,
+                  new Object[]{null, null},
+                  null
+              )
+          ),
+          NullHandling.sqlCompatible()
+          ? ImmutableList.of("0", "1", "3", "4", "5")
+          : ImmutableList.of("0", "1", "2", "3", "4", "5")
+      );
+
+
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayLong",
+              ColumnType.LONG_ARRAY,
+              ImmutableList.of(1L, 2L, 3L),
+              null
+          ),
+          ImmutableList.of("0", "2")
+      );
+      assertFilterMatches(
+          NotDimFilter.of(
+              new EqualityFilter(
+                  "nested.arrayLong",
+                  ColumnType.LONG_ARRAY,
+                  ImmutableList.of(1L, 2L, 3L),
+                  null
+              )
+          ),
+          NullHandling.sqlCompatible()
+          ? ImmutableList.of("1", "4", "5")
+          : ImmutableList.of("1", "3", "4", "5")
+      );
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayLong",
+              ColumnType.LONG_ARRAY,
+              new Object[]{1L, 2L, 3L},
+              null
+          ),
+          ImmutableList.of("0", "2")
+      );
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayLong",
+              ColumnType.LONG_ARRAY,
+              ImmutableList.of(),
+              null
+          ),
+          ImmutableList.of("1")
+      );
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayLong",
+              ColumnType.LONG_ARRAY,
+              new Object[]{null},
+              null
+          ),
+          ImmutableList.of("4")
+      );
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayLong",
+              ColumnType.LONG_ARRAY,
+              new Object[]{null, null},
+              null
+          ),
+          ImmutableList.of()
+      );
+      assertFilterMatches(
+          NotDimFilter.of(
+              new EqualityFilter(
+                  "nested.arrayLong",
+                  ColumnType.LONG_ARRAY,
+                  new Object[]{null, null},
+                  null
+              )
+          ),
+          NullHandling.sqlCompatible()
+          ? ImmutableList.of("0", "1", "2", "4", "5")
+          : ImmutableList.of("0", "1", "2", "3", "4", "5")
+      );
+
+      // test loss of precision matching long arrays with double array match 
values
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayLong",
+              ColumnType.DOUBLE_ARRAY,
+              new Object[]{1.0, 2.0, 3.0},
+              null
+          ),
+          ImmutableList.of("0", "2")
+      );
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayLong",
+              ColumnType.DOUBLE_ARRAY,
+              new Object[]{1.1, 2.2, 3.3},
+              null
+          ),
+          ImmutableList.of()
+      );
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayLong",
+              ColumnType.DOUBLE_ARRAY,
+              new Object[]{null},
+              null
+          ),
+          ImmutableList.of("4")
+      );
+
+
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayDouble",
+              ColumnType.DOUBLE_ARRAY,
+              ImmutableList.of(1.1, 2.2, 3.3),
+              null
+          ),
+          ImmutableList.of("0", "1")
+      );
+      assertFilterMatches(
+          NotDimFilter.of(
+              new EqualityFilter(
+                  "nested.arrayDouble",
+                  ColumnType.DOUBLE_ARRAY,
+                  ImmutableList.of(1.1, 2.2, 3.3),
+                  null
+              )
+          ),
+          NullHandling.sqlCompatible()
+          ? ImmutableList.of("2", "3", "4")
+          : ImmutableList.of("2", "3", "4", "5")
+      );
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayDouble",
+              ColumnType.DOUBLE_ARRAY,
+              new Object[]{1.1, 2.2, 3.3},
+              null
+          ),
+          ImmutableList.of("0", "1")
+      );
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayDouble",
+              ColumnType.DOUBLE_ARRAY,
+              ImmutableList.of(),
+              null
+          ),
+          ImmutableList.of("3")
+      );
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayDouble",
+              ColumnType.DOUBLE_ARRAY,
+              new Object[]{null},
+              null
+          ),
+          ImmutableList.of("2")
+      );
+      assertFilterMatches(
+          new EqualityFilter(
+              "nested.arrayDouble",
+              ColumnType.DOUBLE_ARRAY,
+              ImmutableList.of(1.1, 2.2, 3.4),
+              null
+          ),
+          ImmutableList.of()
+      );
+      assertFilterMatches(
+          NotDimFilter.of(
+              new EqualityFilter(
+                  "nested.arrayDouble",
+                  ColumnType.DOUBLE_ARRAY,
+                  ImmutableList.of(1.1, 2.2, 3.4),
+                  null
+              )
+          ),
+          NullHandling.sqlCompatible()
+          ? ImmutableList.of("0", "1", "2", "3", "4")
+          : ImmutableList.of("0", "1", "2", "3", "4", "5")
+      );
+    }
   }
 
   public static class EqualityFilterNonParameterizedTests extends 
InitializedNullHandlingTest
diff --git 
a/processing/src/test/java/org/apache/druid/segment/filter/RangeFilterTests.java
 
b/processing/src/test/java/org/apache/druid/segment/filter/RangeFilterTests.java
index 5c981d81992..c21a2198193 100644
--- 
a/processing/src/test/java/org/apache/druid/segment/filter/RangeFilterTests.java
+++ 
b/processing/src/test/java/org/apache/druid/segment/filter/RangeFilterTests.java
@@ -43,6 +43,7 @@ import org.apache.druid.query.filter.NotDimFilter;
 import org.apache.druid.query.filter.RangeFilter;
 import org.apache.druid.segment.IndexBuilder;
 import org.apache.druid.segment.StorageAdapter;
+import org.apache.druid.segment.TestHelper;
 import org.apache.druid.segment.column.ColumnType;
 import org.apache.druid.testing.InitializedNullHandlingTest;
 import org.junit.AfterClass;
@@ -78,7 +79,17 @@ public class RangeFilterTests
                          10L,
                          new Object[]{"x", "y"},
                          new Object[]{100, 200},
-                         new Object[]{1.1, null, 3.3}
+                         new Object[]{1.1, null, 3.3},
+                         null,
+                         TestHelper.makeMapWithExplicitNull(
+                             "s0", "d",
+                             "d0", 6.6,
+                             "f0", null,
+                             "l0", 10L,
+                             "arrayString", new Object[]{"x", "y"},
+                             "arrayLong", new Object[]{100, 200},
+                             "arrayDouble", new Object[]{1.1, null, 3.3}
+                         )
                      ))
                      .add(makeDefaultSchemaRow(
                          "7",
@@ -91,7 +102,17 @@ public class RangeFilterTests
                          null,
                          new Object[]{null, "hello", "world"},
                          new Object[]{1234, 3456L, null},
-                         new Object[]{1.23, 4.56, 6.78}
+                         new Object[]{1.23, 4.56, 6.78},
+                         null,
+                         TestHelper.makeMapWithExplicitNull(
+                             "s0", "e",
+                             "d0", null,
+                             "f0", 3.0f,
+                             "l0", null,
+                             "arrayString", new Object[]{null, "hello", 
"world"},
+                             "arrayLong", new Object[]{1234, 3456L, null},
+                             "arrayDouble", new Object[]{1.23, 4.56, 6.78}
+                         )
                      ))
                      .build();
 
@@ -1628,6 +1649,196 @@ public class RangeFilterTests
           ImmutableList.of("1", "2", "5")
       );
     }
+
+    @Test
+    public void testNested()
+    {
+      // nested column mirrors the top level columns, so these cases are 
copied from other tests
+      Assume.assumeTrue(canTestArrayColumns());
+      assertFilterMatches(
+          new RangeFilter("nested.d0", ColumnType.DOUBLE, 120.0, 120.03, 
false, false, null),
+          ImmutableList.of("3")
+      );
+      assertFilterMatches(
+          new RangeFilter("nested.d0", ColumnType.FLOAT, 120.02f, 120.03f, 
false, false, null),
+          ImmutableList.of("3")
+      );
+      assertFilterMatches(
+          new RangeFilter("nested.d0", ColumnType.FLOAT, 59.5f, 60.01f, false, 
false, null),
+          ImmutableList.of("4")
+      );
+      assertFilterMatches(
+          new RangeFilter("nested.l0", ColumnType.LONG, 12344L, 12346L, false, 
false, null),
+          ImmutableList.of("5")
+      );
+      assertFilterMatches(
+          new RangeFilter("nested.l0", ColumnType.DOUBLE, 12344.0, 12345.5, 
false, false, null),
+          ImmutableList.of("5")
+      );
+      assertFilterMatches(
+          new RangeFilter("nested.l0", ColumnType.FLOAT, 12344.0f, 12345.5f, 
false, false, null),
+          ImmutableList.of("5")
+      );
+
+      assertFilterMatches(
+          new RangeFilter(
+              "nested.arrayLong",
+              ColumnType.DOUBLE_ARRAY,
+              null,
+              new Object[]{1.0, 2.0, 3.0},
+              true,
+              false,
+              null
+          ),
+          ImmutableList.of("0", "1", "2", "4")
+      );
+      assertFilterMatches(
+          new RangeFilter(
+              "nested.arrayLong",
+              ColumnType.DOUBLE_ARRAY,
+              null,
+              new Object[]{1.0, 2.0, 3.0},
+              true,
+              true,
+              null
+          ),
+          ImmutableList.of("1", "4")
+      );
+      assertFilterMatches(
+          new RangeFilter(
+              "nested.arrayLong",
+              ColumnType.DOUBLE_ARRAY,
+              null,
+              new Object[]{1.1, 2.1, 3.1},
+              true,
+              true,
+              null
+          ),
+          ImmutableList.of("0", "1", "2", "4")
+      );
+
+      assertFilterMatches(
+          new RangeFilter(
+              "nested.arrayLong",
+              ColumnType.DOUBLE_ARRAY,
+              new Object[]{1.0, 2.0, 3.0},
+              null,
+              false,
+              false,
+              null
+          ),
+          ImmutableList.of("0", "2", "5", "6", "7")
+      );
+      assertFilterMatches(
+          new RangeFilter(
+              "nested.arrayLong",
+              ColumnType.DOUBLE_ARRAY,
+              new Object[]{0.8, 1.8, 2.8},
+              null,
+              false,
+              false,
+              null
+          ),
+          ImmutableList.of("0", "2", "5", "6", "7")
+      );
+      assertFilterMatches(
+          new RangeFilter(
+              "nested.arrayLong",
+              ColumnType.DOUBLE_ARRAY,
+              new Object[]{0.8, 1.8, 2.8},
+              null,
+              true,
+              false,
+              null
+          ),
+          ImmutableList.of("0", "2", "5", "6", "7")
+      );
+      assertFilterMatches(
+          new RangeFilter(
+              "nested.arrayLong",
+              ColumnType.DOUBLE_ARRAY,
+              new Object[]{1.0, 2.0, 3.0},
+              null,
+              true,
+              true,
+              null
+          ),
+          ImmutableList.of("5", "6", "7")
+      );
+      assertFilterMatches(
+          new RangeFilter(
+              "nested.arrayLong",
+              ColumnType.DOUBLE_ARRAY,
+              new Object[]{1.1, 2.1, 3.1},
+              null,
+              false,
+              true,
+              null
+          ),
+          ImmutableList.of("5", "6", "7")
+      );
+      assertFilterMatches(
+          new RangeFilter(
+              "nested.arrayLong",
+              ColumnType.DOUBLE_ARRAY,
+              new Object[]{1.1, 2.1, 3.1},
+              null,
+              true,
+              true,
+              null
+          ),
+          ImmutableList.of("5", "6", "7")
+      );
+
+      assertFilterMatches(
+          new RangeFilter(
+              "nested.arrayLong",
+              ColumnType.DOUBLE_ARRAY,
+              new Object[]{0.8, 1.8, 2.8},
+              new Object[]{1.1, 2.1, 3.1},
+              true,
+              true,
+              null
+          ),
+          ImmutableList.of("0", "2")
+      );
+      assertFilterMatches(
+          new RangeFilter(
+              "nested.arrayLong",
+              ColumnType.DOUBLE_ARRAY,
+              new Object[]{0.8, 1.8, 2.8},
+              new Object[]{1.1, 2.1, 3.1},
+              false,
+              true,
+              null
+          ),
+          ImmutableList.of("0", "2")
+      );
+      assertFilterMatches(
+          new RangeFilter(
+              "nested.arrayLong",
+              ColumnType.DOUBLE_ARRAY,
+              new Object[]{0.8, 1.8, 2.8},
+              new Object[]{1.1, 2.1, 3.1},
+              true,
+              false,
+              null
+          ),
+          ImmutableList.of("0", "2")
+      );
+      assertFilterMatches(
+          new RangeFilter(
+              "nested.arrayLong",
+              ColumnType.DOUBLE_ARRAY,
+              new Object[]{0.8, 1.8, 2.8},
+              new Object[]{1.1, 2.1, 3.1},
+              false,
+              false,
+              null
+          ),
+          ImmutableList.of("0", "2")
+      );
+    }
   }
 
   public static class RangeFilterNonParameterizedTests extends 
InitializedNullHandlingTest
diff --git 
a/processing/src/test/java/org/apache/druid/segment/nested/NestedFieldColumnIndexSupplierTest.java
 
b/processing/src/test/java/org/apache/druid/segment/nested/NestedFieldColumnIndexSupplierTest.java
index a3ad411e2c7..8ed9ad23fdb 100644
--- 
a/processing/src/test/java/org/apache/druid/segment/nested/NestedFieldColumnIndexSupplierTest.java
+++ 
b/processing/src/test/java/org/apache/druid/segment/nested/NestedFieldColumnIndexSupplierTest.java
@@ -35,6 +35,8 @@ import org.apache.druid.segment.column.TypeStrategies;
 import org.apache.druid.segment.data.BitmapSerdeFactory;
 import org.apache.druid.segment.data.FixedIndexed;
 import org.apache.druid.segment.data.FixedIndexedWriter;
+import org.apache.druid.segment.data.FrontCodedIntArrayIndexed;
+import org.apache.druid.segment.data.FrontCodedIntArrayIndexedWriter;
 import org.apache.druid.segment.data.GenericIndexed;
 import org.apache.druid.segment.data.GenericIndexedWriter;
 import org.apache.druid.segment.data.Indexed;
@@ -86,6 +88,7 @@ public class NestedFieldColumnIndexSupplierTest extends 
InitializedNullHandlingT
   Supplier<Indexed<ByteBuffer>> globalStrings;
   Supplier<FixedIndexed<Long>> globalLongs;
   Supplier<FixedIndexed<Double>> globalDoubles;
+  Supplier<FrontCodedIntArrayIndexed> globalArrays;
 
 
   @Before
@@ -94,6 +97,8 @@ public class NestedFieldColumnIndexSupplierTest extends 
InitializedNullHandlingT
     ByteBuffer stringBuffer = ByteBuffer.allocate(1 << 12);
     ByteBuffer longBuffer = ByteBuffer.allocate(1 << 
12).order(ByteOrder.nativeOrder());
     ByteBuffer doubleBuffer = ByteBuffer.allocate(1 << 
12).order(ByteOrder.nativeOrder());
+    ByteBuffer arrayBuffer = ByteBuffer.allocate(1 << 
12).order(ByteOrder.nativeOrder());
+
 
     GenericIndexedWriter<String> stringWriter = new GenericIndexedWriter<>(
         new OnHeapMemorySegmentWriteOutMedium(),
@@ -148,10 +153,19 @@ public class NestedFieldColumnIndexSupplierTest extends 
InitializedNullHandlingT
     doubleWriter.write(9.9);
     writeToBuffer(doubleBuffer, doubleWriter);
 
+    FrontCodedIntArrayIndexedWriter arrayWriter = new 
FrontCodedIntArrayIndexedWriter(
+        new OnHeapMemorySegmentWriteOutMedium(),
+        ByteOrder.nativeOrder(),
+        4
+    );
+    arrayWriter.open();
+    writeToBuffer(arrayBuffer, arrayWriter);
+
     GenericIndexed<ByteBuffer> strings = GenericIndexed.read(stringBuffer, 
GenericIndexed.UTF8_STRATEGY);
     globalStrings = () -> strings.singleThreaded();
     globalLongs = FixedIndexed.read(longBuffer, TypeStrategies.LONG, 
ByteOrder.nativeOrder(), Long.BYTES);
     globalDoubles = FixedIndexed.read(doubleBuffer, TypeStrategies.DOUBLE, 
ByteOrder.nativeOrder(), Double.BYTES);
+    globalArrays = FrontCodedIntArrayIndexed.read(arrayBuffer, 
ByteOrder.nativeOrder());
   }
 
   @Test
@@ -1309,6 +1323,7 @@ public class NestedFieldColumnIndexSupplierTest extends 
InitializedNullHandlingT
         stringIndexed,
         longIndexed,
         doubleIndexed,
+        globalArrays,
         null,
         null,
         ROW_COUNT
@@ -1509,6 +1524,7 @@ public class NestedFieldColumnIndexSupplierTest extends 
InitializedNullHandlingT
         globalStrings,
         globalLongs,
         globalDoubles,
+        globalArrays,
         null,
         null,
         ROW_COUNT
@@ -1593,6 +1609,7 @@ public class NestedFieldColumnIndexSupplierTest extends 
InitializedNullHandlingT
         globalStrings,
         globalLongs,
         globalDoubles,
+        globalArrays,
         null,
         null,
         ROW_COUNT
@@ -1673,6 +1690,7 @@ public class NestedFieldColumnIndexSupplierTest extends 
InitializedNullHandlingT
         globalStrings,
         globalLongs,
         globalDoubles,
+        globalArrays,
         null,
         null,
         ROW_COUNT
@@ -1758,6 +1776,7 @@ public class NestedFieldColumnIndexSupplierTest extends 
InitializedNullHandlingT
         globalStrings,
         globalLongs,
         globalDoubles,
+        globalArrays,
         null,
         null,
         ROW_COUNT
@@ -1838,6 +1857,7 @@ public class NestedFieldColumnIndexSupplierTest extends 
InitializedNullHandlingT
         globalStrings,
         globalLongs,
         globalDoubles,
+        globalArrays,
         null,
         null,
         ROW_COUNT
@@ -1923,6 +1943,7 @@ public class NestedFieldColumnIndexSupplierTest extends 
InitializedNullHandlingT
         globalStrings,
         globalLongs,
         globalDoubles,
+        globalArrays,
         null,
         null,
         ROW_COUNT
@@ -2018,6 +2039,7 @@ public class NestedFieldColumnIndexSupplierTest extends 
InitializedNullHandlingT
         globalStrings,
         globalLongs,
         globalDoubles,
+        globalArrays,
         null,
         null,
         ROW_COUNT


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

Reply via email to