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

fjy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-druid.git


The following commit(s) were added to refs/heads/master by this push:
     new f09e718  Implement MapVirtualColumn.makeDimensionSelector properly 
(#6396)
f09e718 is described below

commit f09e718c6813c866591501236285166655c85bf8
Author: Jihoon Son <[email protected]>
AuthorDate: Sat Sep 29 14:13:05 2018 -0700

    Implement MapVirtualColumn.makeDimensionSelector properly (#6396)
    
    * Implement MapVirtualColumn.makeDimensionSelector properly
    
    * address comments
---
 .../MapTypeMapVirtualColumnDimensionSelector.java  | 142 +++++++++++++++
 .../org/apache/druid/segment/MapVirtualColumn.java |  60 ++-----
 .../segment/MapVirtualColumnDimensionSelector.java |  75 ++++++++
 .../segment/MapVirtualColumnValueSelector.java     |  68 +++++++
 ...tringTypeMapVirtualColumnDimensionSelector.java | 197 +++++++++++++++++++++
 .../druid/segment/MapVirtualColumnGroupByTest.java | 174 ++++++++++++++++++
 ...mnTest.java => MapVirtualColumnSelectTest.java} |  28 +--
 .../druid/segment/MapVirtualColumnTestBase.java    |  81 +++++++++
 .../druid/segment/MapVirtualColumnTopNTest.java    | 145 +++++++++++++++
 .../query/groupby/GroupByQueryMergeBufferTest.java |   1 -
 .../java/org/apache/druid/segment/TestIndex.java   |   6 +-
 11 files changed, 905 insertions(+), 72 deletions(-)

diff --git 
a/extensions-contrib/virtual-columns/src/main/java/org/apache/druid/segment/MapTypeMapVirtualColumnDimensionSelector.java
 
b/extensions-contrib/virtual-columns/src/main/java/org/apache/druid/segment/MapTypeMapVirtualColumnDimensionSelector.java
new file mode 100644
index 0000000..45d20cb
--- /dev/null
+++ 
b/extensions-contrib/virtual-columns/src/main/java/org/apache/druid/segment/MapTypeMapVirtualColumnDimensionSelector.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.druid.segment;
+
+import com.google.common.base.Predicate;
+import org.apache.druid.query.filter.ValueMatcher;
+import org.apache.druid.query.monomorphicprocessing.RuntimeShapeInspector;
+import org.apache.druid.segment.data.IndexedInts;
+
+import javax.annotation.Nullable;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+/**
+ * {@link DimensionSelector} for {@link Map} type {@link MapVirtualColumn}. 
This dimensionSelector only supports
+ * {@link #getObject()} currently.
+ */
+final class MapTypeMapVirtualColumnDimensionSelector extends 
MapVirtualColumnDimensionSelector
+{
+  MapTypeMapVirtualColumnDimensionSelector(
+      DimensionSelector keySelector,
+      DimensionSelector valueSelector
+  )
+  {
+    super(keySelector, valueSelector);
+  }
+
+  @Override
+  public IndexedInts getRow()
+  {
+    throw new UnsupportedOperationException("Map column doesn't support 
getRow()");
+  }
+
+  @Override
+  public ValueMatcher makeValueMatcher(@Nullable String value)
+  {
+    return new ValueMatcher()
+    {
+      @Override
+      public boolean matches()
+      {
+        // Map column doesn't match with any string
+        return false;
+      }
+
+      @Override
+      public void inspectRuntimeShape(RuntimeShapeInspector inspector)
+      {
+
+      }
+    };
+  }
+
+  @Override
+  public ValueMatcher makeValueMatcher(Predicate<String> predicate)
+  {
+    return new ValueMatcher()
+    {
+      @Override
+      public boolean matches()
+      {
+        return false;
+      }
+
+      @Override
+      public void inspectRuntimeShape(RuntimeShapeInspector inspector)
+      {
+
+      }
+    };
+  }
+
+  @Override
+  public int getValueCardinality()
+  {
+    return CARDINALITY_UNKNOWN;
+  }
+
+  @Nullable
+  @Override
+  public String lookupName(int id)
+  {
+    throw new UnsupportedOperationException("Map column doesn't support 
lookupName()");
+  }
+
+  @Override
+  public boolean nameLookupPossibleInAdvance()
+  {
+    return false;
+  }
+
+  @Nullable
+  @Override
+  public IdLookup idLookup()
+  {
+    throw new UnsupportedOperationException("Map column doesn't support 
idLookup()");
+  }
+
+  @Override
+  public Object getObject()
+  {
+    final DimensionSelector keySelector = getKeySelector();
+    final DimensionSelector valueSelector = getValueSelector();
+
+    final IndexedInts keyIndices = keySelector.getRow();
+    final IndexedInts valueIndices = valueSelector.getRow();
+
+    final int limit = Math.min(keyIndices.size(), valueIndices.size());
+    return IntStream
+        .range(0, limit)
+        .boxed()
+        .collect(
+            Collectors.toMap(
+                i -> keySelector.lookupName(keyIndices.get(i)),
+                i -> valueSelector.lookupName(valueIndices.get(i))
+            )
+        );
+  }
+
+  @Override
+  public Class classOfObject()
+  {
+    return Map.class;
+  }
+}
diff --git 
a/extensions-contrib/virtual-columns/src/main/java/org/apache/druid/segment/MapVirtualColumn.java
 
b/extensions-contrib/virtual-columns/src/main/java/org/apache/druid/segment/MapVirtualColumn.java
index fdded43..7451398 100644
--- 
a/extensions-contrib/virtual-columns/src/main/java/org/apache/druid/segment/MapVirtualColumn.java
+++ 
b/extensions-contrib/virtual-columns/src/main/java/org/apache/druid/segment/MapVirtualColumn.java
@@ -24,12 +24,10 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Maps;
-import org.apache.druid.common.config.NullHandling;
 import org.apache.druid.java.util.common.StringUtils;
 import org.apache.druid.query.dimension.DefaultDimensionSpec;
 import org.apache.druid.query.dimension.DimensionSpec;
 import org.apache.druid.query.filter.DimFilterUtils;
-import org.apache.druid.query.monomorphicprocessing.RuntimeShapeInspector;
 import org.apache.druid.segment.column.ColumnCapabilities;
 import org.apache.druid.segment.column.ColumnCapabilitiesImpl;
 import org.apache.druid.segment.column.ValueType;
@@ -69,8 +67,16 @@ public class MapVirtualColumn implements VirtualColumn
   @Override
   public DimensionSelector makeDimensionSelector(DimensionSpec dimensionSpec, 
ColumnSelectorFactory factory)
   {
-    // Could probably do something useful here if the column name is 
dot-style. But for now just return nothing.
-    return 
dimensionSpec.decorate(DimensionSelectorUtils.constantSelector(null, 
dimensionSpec.getExtractionFn()));
+    final DimensionSelector keySelector = 
factory.makeDimensionSelector(DefaultDimensionSpec.of(keyDimension));
+    final DimensionSelector valueSelector = 
factory.makeDimensionSelector(DefaultDimensionSpec.of(valueDimension));
+    final String subColumnName = 
VirtualColumns.splitColumnName(dimensionSpec.getDimension()).rhs;
+    if (subColumnName == null) {
+      return dimensionSpec.decorate(new 
MapTypeMapVirtualColumnDimensionSelector(keySelector, valueSelector));
+    } else {
+      return dimensionSpec.decorate(
+          new StringTypeMapVirtualColumnDimensionSelector(keySelector, 
valueSelector, subColumnName)
+      );
+    }
   }
 
   @Override
@@ -164,52 +170,6 @@ public class MapVirtualColumn implements VirtualColumn
     }
   }
 
-  private abstract static class MapVirtualColumnValueSelector<T> implements 
ColumnValueSelector<T>
-  {
-    final DimensionSelector keySelector;
-    final DimensionSelector valueSelector;
-
-    private MapVirtualColumnValueSelector(DimensionSelector keySelector, 
DimensionSelector valueSelector)
-    {
-      this.keySelector = keySelector;
-      this.valueSelector = valueSelector;
-    }
-
-    @Override
-    public double getDouble()
-    {
-      assert NullHandling.replaceWithDefault();
-      return 0.0;
-    }
-
-    @Override
-    public float getFloat()
-    {
-      assert NullHandling.replaceWithDefault();
-      return 0.0f;
-    }
-
-    @Override
-    public long getLong()
-    {
-      assert NullHandling.replaceWithDefault();
-      return 0L;
-    }
-
-    @Override
-    public boolean isNull()
-    {
-      return false;
-    }
-
-    @Override
-    public void inspectRuntimeShape(RuntimeShapeInspector inspector)
-    {
-      inspector.visit("keySelector", keySelector);
-      inspector.visit("valueSelector", valueSelector);
-    }
-  }
-
   @Override
   public ColumnCapabilities capabilities(String columnName)
   {
diff --git 
a/extensions-contrib/virtual-columns/src/main/java/org/apache/druid/segment/MapVirtualColumnDimensionSelector.java
 
b/extensions-contrib/virtual-columns/src/main/java/org/apache/druid/segment/MapVirtualColumnDimensionSelector.java
new file mode 100644
index 0000000..2c56df4
--- /dev/null
+++ 
b/extensions-contrib/virtual-columns/src/main/java/org/apache/druid/segment/MapVirtualColumnDimensionSelector.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.druid.segment;
+
+import org.apache.druid.common.config.NullHandling;
+import org.apache.druid.query.monomorphicprocessing.RuntimeShapeInspector;
+
+abstract class MapVirtualColumnDimensionSelector implements DimensionSelector
+{
+  private final DimensionSelector keySelector;
+  private final DimensionSelector valueSelector;
+
+  MapVirtualColumnDimensionSelector(
+      DimensionSelector keySelector,
+      DimensionSelector valueSelector
+  )
+  {
+    this.keySelector = keySelector;
+    this.valueSelector = valueSelector;
+  }
+
+  protected DimensionSelector getKeySelector()
+  {
+    return keySelector;
+  }
+
+  protected DimensionSelector getValueSelector()
+  {
+    return valueSelector;
+  }
+
+  @Override
+  public double getDouble()
+  {
+    assert NullHandling.replaceWithDefault();
+    return 0.0;
+  }
+
+  @Override
+  public float getFloat()
+  {
+    assert NullHandling.replaceWithDefault();
+    return 0.0f;
+  }
+
+  @Override
+  public long getLong()
+  {
+    assert NullHandling.replaceWithDefault();
+    return 0L;
+  }
+
+  @Override
+  public void inspectRuntimeShape(RuntimeShapeInspector inspector)
+  {
+    inspector.visit("keySelector", keySelector);
+    inspector.visit("valueSelector", valueSelector);
+  }
+}
diff --git 
a/extensions-contrib/virtual-columns/src/main/java/org/apache/druid/segment/MapVirtualColumnValueSelector.java
 
b/extensions-contrib/virtual-columns/src/main/java/org/apache/druid/segment/MapVirtualColumnValueSelector.java
new file mode 100644
index 0000000..ba25bb0
--- /dev/null
+++ 
b/extensions-contrib/virtual-columns/src/main/java/org/apache/druid/segment/MapVirtualColumnValueSelector.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.druid.segment;
+
+import org.apache.druid.common.config.NullHandling;
+import org.apache.druid.query.monomorphicprocessing.RuntimeShapeInspector;
+
+abstract class MapVirtualColumnValueSelector<T> implements 
ColumnValueSelector<T>
+{
+  private final DimensionSelector keySelector;
+  private final DimensionSelector valueSelector;
+
+  MapVirtualColumnValueSelector(DimensionSelector keySelector, 
DimensionSelector valueSelector)
+  {
+    this.keySelector = keySelector;
+    this.valueSelector = valueSelector;
+  }
+
+  @Override
+  public double getDouble()
+  {
+    assert NullHandling.replaceWithDefault();
+    return 0.0;
+  }
+
+  @Override
+  public float getFloat()
+  {
+    assert NullHandling.replaceWithDefault();
+    return 0.0f;
+  }
+
+  @Override
+  public long getLong()
+  {
+    assert NullHandling.replaceWithDefault();
+    return 0L;
+  }
+
+  @Override
+  public boolean isNull()
+  {
+    return false;
+  }
+
+  @Override
+  public void inspectRuntimeShape(RuntimeShapeInspector inspector)
+  {
+    inspector.visit("keySelector", keySelector);
+    inspector.visit("valueSelector", valueSelector);
+  }
+}
diff --git 
a/extensions-contrib/virtual-columns/src/main/java/org/apache/druid/segment/StringTypeMapVirtualColumnDimensionSelector.java
 
b/extensions-contrib/virtual-columns/src/main/java/org/apache/druid/segment/StringTypeMapVirtualColumnDimensionSelector.java
new file mode 100644
index 0000000..9b15a29
--- /dev/null
+++ 
b/extensions-contrib/virtual-columns/src/main/java/org/apache/druid/segment/StringTypeMapVirtualColumnDimensionSelector.java
@@ -0,0 +1,197 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.druid.segment;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import org.apache.druid.query.filter.ValueMatcher;
+import org.apache.druid.query.monomorphicprocessing.RuntimeShapeInspector;
+import org.apache.druid.segment.data.IndexedInts;
+import org.apache.druid.segment.data.SingleIndexedInt;
+import org.apache.druid.segment.data.ZeroIndexedInts;
+
+import javax.annotation.Nullable;
+import java.util.Objects;
+import java.util.stream.IntStream;
+
+/**
+ * {@link DimensionSelector} for String type {@link MapVirtualColumn}. The 
performance has not considered yet and so
+ * it may need to be improved later.
+ */
+final class StringTypeMapVirtualColumnDimensionSelector extends 
MapVirtualColumnDimensionSelector
+{
+  private final String subColumnName;
+  private final SingleIndexedInt indexedInt = new SingleIndexedInt();
+
+  StringTypeMapVirtualColumnDimensionSelector(
+      DimensionSelector keySelector,
+      DimensionSelector valueSelector,
+      String subColumnName
+  )
+  {
+    super(keySelector, valueSelector);
+    this.subColumnName = Preconditions.checkNotNull(subColumnName, 
"subColumnName");
+  }
+
+  @Override
+  public IndexedInts getRow()
+  {
+    final int valueIndex = findValueIndicesIndexForSubColumn();
+    if (valueIndex < 0) {
+      return ZeroIndexedInts.instance();
+    } else {
+      indexedInt.setValue(valueIndex);
+      return indexedInt;
+    }
+  }
+
+  @Override
+  public ValueMatcher makeValueMatcher(@Nullable String value)
+  {
+    return new ValueMatcher()
+    {
+      @Override
+      public boolean matches()
+      {
+        return Objects.equals(value, getObject());
+      }
+
+      @Override
+      public void inspectRuntimeShape(RuntimeShapeInspector inspector)
+      {
+        inspector.visit("keySelector", getKeySelector());
+        inspector.visit("valueSelector", getValueSelector());
+        inspector.visit("subColumnName", subColumnName);
+      }
+    };
+  }
+
+  @Override
+  public ValueMatcher makeValueMatcher(Predicate<String> predicate)
+  {
+    return new ValueMatcher()
+    {
+      @Override
+      public boolean matches()
+      {
+        return predicate.apply((String) getObject());
+      }
+
+      @Override
+      public void inspectRuntimeShape(RuntimeShapeInspector inspector)
+      {
+        inspector.visit("keySelector", getKeySelector());
+        inspector.visit("valueSelector", getValueSelector());
+        inspector.visit("subColumnName", subColumnName);
+      }
+    };
+  }
+
+  @Override
+  public int getValueCardinality()
+  {
+    // To get the value cardinarlity, we need to first check all keys and 
values to find valid pairs, and then find the
+    // number of distinct values among them.
+    return CARDINALITY_UNKNOWN;
+  }
+
+  @Nullable
+  @Override
+  public String lookupName(int id)
+  {
+    final int valueIndex = findValueIndicesIndexForSubColumn();
+
+    if (valueIndex == id) {
+      return getValueSelector().lookupName(id);
+    } else {
+      return null;
+    }
+  }
+
+  @Override
+  public boolean nameLookupPossibleInAdvance()
+  {
+    return false;
+  }
+
+  @Nullable
+  @Override
+  public IdLookup idLookup()
+  {
+    final DimensionSelector valueSelector = getValueSelector();
+    final IdLookup valueLookup = valueSelector.idLookup();
+
+    if (valueLookup != null) {
+      final int valueIndex = findValueIndicesIndexForSubColumn();
+      return name -> {
+        final int candidate = valueLookup.lookupId(name);
+        if (candidate == valueIndex) {
+          return candidate;
+        }
+        return -1;
+      };
+    } else {
+      return null;
+    }
+  }
+
+  @Nullable
+  @Override
+  public Object getObject()
+  {
+    final int valueIndex = findValueIndicesIndexForSubColumn();
+
+    if (valueIndex < 0) {
+      return null;
+    } else {
+      final DimensionSelector valueSelector = getValueSelector();
+      final IndexedInts valueIndices = valueSelector.getRow();
+      return valueSelector.lookupName(valueIndices.get(valueIndex));
+    }
+  }
+
+  /**
+   * Find the index of valueIndices which is {@link IndexedInts} returned from 
{@link #getValueSelector()#getRow()}
+   * corresponding to the {@link #subColumnName}.
+   *
+   * @return index for valueIndices if found. -1 otherwise.
+   */
+  private int findValueIndicesIndexForSubColumn()
+  {
+    final DimensionSelector keySelector = getKeySelector();
+    final DimensionSelector valueSelector = getValueSelector();
+
+    final IndexedInts keyIndices = keySelector.getRow();
+    final IndexedInts valueIndices = valueSelector.getRow();
+
+    final int limit = Math.min(keyIndices.size(), valueIndices.size());
+
+    return IntStream
+        .range(0, limit)
+        .filter(i -> 
subColumnName.equals(keySelector.lookupName(keyIndices.get(i)))) // 
subColumnName is never null
+        .findAny()
+        .orElse(-1);
+  }
+
+  @Override
+  public Class classOfObject()
+  {
+    return String.class;
+  }
+}
diff --git 
a/extensions-contrib/virtual-columns/src/test/java/org/apache/druid/segment/MapVirtualColumnGroupByTest.java
 
b/extensions-contrib/virtual-columns/src/test/java/org/apache/druid/segment/MapVirtualColumnGroupByTest.java
new file mode 100644
index 0000000..43d6809
--- /dev/null
+++ 
b/extensions-contrib/virtual-columns/src/test/java/org/apache/druid/segment/MapVirtualColumnGroupByTest.java
@@ -0,0 +1,174 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.druid.segment;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.druid.collections.DefaultBlockingPool;
+import org.apache.druid.collections.StupidPool;
+import org.apache.druid.data.input.MapBasedRow;
+import org.apache.druid.data.input.Row;
+import org.apache.druid.jackson.DefaultObjectMapper;
+import org.apache.druid.java.util.common.DateTimes;
+import org.apache.druid.java.util.common.Intervals;
+import org.apache.druid.java.util.common.granularity.Granularities;
+import org.apache.druid.query.DruidProcessingConfig;
+import org.apache.druid.query.QueryPlus;
+import org.apache.druid.query.QueryRunner;
+import org.apache.druid.query.QueryRunnerTestHelper;
+import org.apache.druid.query.TableDataSource;
+import org.apache.druid.query.aggregation.CountAggregatorFactory;
+import org.apache.druid.query.dimension.DefaultDimensionSpec;
+import org.apache.druid.query.groupby.GroupByQuery;
+import org.apache.druid.query.groupby.GroupByQueryConfig;
+import org.apache.druid.query.groupby.GroupByQueryQueryToolChest;
+import org.apache.druid.query.groupby.GroupByQueryRunnerFactory;
+import org.apache.druid.query.groupby.strategy.GroupByStrategySelector;
+import org.apache.druid.query.groupby.strategy.GroupByStrategyV2;
+import org.apache.druid.query.spec.MultipleIntervalSegmentSpec;
+import org.apache.druid.segment.incremental.IncrementalIndex;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.List;
+
+public class MapVirtualColumnGroupByTest
+{
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  private QueryRunner<Row> runner;
+
+  @Before
+  public void setup() throws IOException
+  {
+    final IncrementalIndex incrementalIndex = 
MapVirtualColumnTestBase.generateIndex();
+
+    final GroupByStrategySelector strategySelector = new 
GroupByStrategySelector(
+        GroupByQueryConfig::new,
+        null,
+        new GroupByStrategyV2(
+            new DruidProcessingConfig()
+            {
+              @Override
+              public String getFormatString()
+              {
+                return null;
+              }
+
+              @Override
+              public int intermediateComputeSizeBytes()
+              {
+                return 10 * 1024 * 1024;
+              }
+
+              @Override
+              public int getNumMergeBuffers()
+              {
+                return 1;
+              }
+
+              @Override
+              public int getNumThreads()
+              {
+                return 1;
+              }
+            },
+            GroupByQueryConfig::new,
+            new StupidPool<>("map-virtual-column-groupby-test", () -> 
ByteBuffer.allocate(1024)),
+            new DefaultBlockingPool<>(() -> ByteBuffer.allocate(1024), 1),
+            new DefaultObjectMapper(),
+            QueryRunnerTestHelper.NOOP_QUERYWATCHER
+        )
+    );
+
+    final GroupByQueryRunnerFactory factory = new GroupByQueryRunnerFactory(
+        strategySelector,
+        new GroupByQueryQueryToolChest(
+            strategySelector,
+            QueryRunnerTestHelper.NoopIntervalChunkingQueryRunnerDecorator()
+        )
+    );
+
+    runner = QueryRunnerTestHelper.makeQueryRunner(
+        factory,
+        "index",
+        new IncrementalIndexSegment(incrementalIndex, "index"),
+        "incremental"
+    );
+  }
+
+  @Test
+  public void testWithMapColumn()
+  {
+    final GroupByQuery query = new GroupByQuery(
+        new TableDataSource(QueryRunnerTestHelper.dataSource),
+        new 
MultipleIntervalSegmentSpec(ImmutableList.of(Intervals.of("2011/2012"))),
+        VirtualColumns.create(ImmutableList.of(new MapVirtualColumn("keys", 
"values", "params"))),
+        null,
+        Granularities.ALL,
+        ImmutableList.of(new DefaultDimensionSpec("params", "params")),
+        ImmutableList.of(new CountAggregatorFactory("count")),
+        null,
+        null,
+        null,
+        null,
+        null
+    );
+
+    expectedException.expect(UnsupportedOperationException.class);
+    expectedException.expectMessage("Map column doesn't support getRow()");
+    runner.run(QueryPlus.wrap(query), new HashMap<>()).toList();
+  }
+
+  @Test
+  public void testWithSubColumn()
+  {
+    final GroupByQuery query = new GroupByQuery(
+        new TableDataSource(QueryRunnerTestHelper.dataSource),
+        new 
MultipleIntervalSegmentSpec(ImmutableList.of(Intervals.of("2011/2012"))),
+        VirtualColumns.create(ImmutableList.of(new MapVirtualColumn("keys", 
"values", "params"))),
+        null,
+        Granularities.ALL,
+        ImmutableList.of(new DefaultDimensionSpec("params.key3", 
"params.key3")),
+        ImmutableList.of(new CountAggregatorFactory("count")),
+        null,
+        null,
+        null,
+        null,
+        null
+    );
+
+    final List<Row> result = runner.run(QueryPlus.wrap(query), new 
HashMap<>()).toList();
+    final List<Row> expected = ImmutableList.of(
+        new MapBasedRow(
+            DateTimes.of("2011-01-12T00:00:00.000Z"),
+            MapVirtualColumnTestBase.mapOf("count", 1L, "params.key3", 
"value3")
+        ),
+        new MapBasedRow(DateTimes.of("2011-01-12T00:00:00.000Z"), 
MapVirtualColumnTestBase.mapOf("count", 2L))
+    );
+
+    Assert.assertEquals(expected, result);
+  }
+}
diff --git 
a/extensions-contrib/virtual-columns/src/test/java/org/apache/druid/segment/MapVirtualColumnTest.java
 
b/extensions-contrib/virtual-columns/src/test/java/org/apache/druid/segment/MapVirtualColumnSelectTest.java
similarity index 91%
rename from 
extensions-contrib/virtual-columns/src/test/java/org/apache/druid/segment/MapVirtualColumnTest.java
rename to 
extensions-contrib/virtual-columns/src/test/java/org/apache/druid/segment/MapVirtualColumnSelectTest.java
index 7f7c438..9ff2f94 100644
--- 
a/extensions-contrib/virtual-columns/src/test/java/org/apache/druid/segment/MapVirtualColumnTest.java
+++ 
b/extensions-contrib/virtual-columns/src/test/java/org/apache/druid/segment/MapVirtualColumnSelectTest.java
@@ -23,7 +23,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.base.Supplier;
 import com.google.common.base.Suppliers;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
 import com.google.common.io.CharSource;
 import org.apache.druid.data.input.impl.DelimitedParseSpec;
 import org.apache.druid.data.input.impl.DimensionsSpec;
@@ -60,7 +59,7 @@ import java.util.Map;
 /**
  */
 @RunWith(Parameterized.class)
-public class MapVirtualColumnTest
+public class MapVirtualColumnSelectTest
 {
   @Parameterized.Parameters
   public static Iterable<Object[]> constructorFeeder() throws IOException
@@ -104,7 +103,7 @@ public class MapVirtualColumnTest
         "2011-01-12T00:00:00.000Z\tc\tkey1,key5\tvalue1,value5,value9\n"
     );
 
-    IncrementalIndex index1 = TestIndex.loadIncrementalIndex(index, input, 
parser);
+    IncrementalIndex index1 = TestIndex.loadIncrementalIndex(() -> index, 
input, parser);
     QueryableIndex index2 = TestIndex.persistRealtimeAndLoadMMapped(index1);
 
     return QueryRunnerTestHelper.transformToConstructionFeeder(
@@ -127,7 +126,7 @@ public class MapVirtualColumnTest
 
   private final QueryRunner runner;
 
-  public MapVirtualColumnTest(QueryRunner runner)
+  public MapVirtualColumnSelectTest(QueryRunner runner)
   {
     this.runner = runner;
   }
@@ -159,26 +158,26 @@ public class MapVirtualColumnTest
     Druids.SelectQueryBuilder builder = testBuilder();
 
     List<Map> expectedResults = Arrays.asList(
-        mapOf(
+        MapVirtualColumnTestBase.mapOf(
             "dim", "a",
             "params.key1", "value1",
             "params.key3", "value3",
             "params.key5", null,
-            "params", mapOf("key1", "value1", "key2", "value2", "key3", 
"value3")
+            "params", MapVirtualColumnTestBase.mapOf("key1", "value1", "key2", 
"value2", "key3", "value3")
         ),
-        mapOf(
+        MapVirtualColumnTestBase.mapOf(
             "dim", "b",
             "params.key1", null,
             "params.key3", null,
             "params.key5", null,
-            "params", mapOf("key4", "value4")
+            "params", MapVirtualColumnTestBase.mapOf("key4", "value4")
         ),
-        mapOf(
+        MapVirtualColumnTestBase.mapOf(
             "dim", "c",
             "params.key1", "value1",
             "params.key3", null,
             "params.key5", "value5",
-            "params", mapOf("key1", "value1", "key5", "value5")
+            "params", MapVirtualColumnTestBase.mapOf("key1", "value1", "key5", 
"value5")
         )
     );
     List<VirtualColumn> virtualColumns = Collections.singletonList(new 
MapVirtualColumn("keys", "values", "params"));
@@ -189,15 +188,6 @@ public class MapVirtualColumnTest
     checkSelectQuery(selectQuery, expectedResults);
   }
 
-  private Map mapOf(Object... elements)
-  {
-    Map map = Maps.newHashMap();
-    for (int i = 0; i < elements.length; i += 2) {
-      map.put(elements[i], elements[i + 1]);
-    }
-    return map;
-  }
-
   private void checkSelectQuery(SelectQuery searchQuery, List<Map> expected)
   {
     List<Result<SelectResultValue>> results = 
runner.run(QueryPlus.wrap(searchQuery), ImmutableMap.of()).toList();
diff --git 
a/extensions-contrib/virtual-columns/src/test/java/org/apache/druid/segment/MapVirtualColumnTestBase.java
 
b/extensions-contrib/virtual-columns/src/test/java/org/apache/druid/segment/MapVirtualColumnTestBase.java
new file mode 100644
index 0000000..7736ee2
--- /dev/null
+++ 
b/extensions-contrib/virtual-columns/src/test/java/org/apache/druid/segment/MapVirtualColumnTestBase.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.druid.segment;
+
+import com.google.common.io.CharSource;
+import org.apache.druid.data.input.impl.DelimitedParseSpec;
+import org.apache.druid.data.input.impl.DimensionsSpec;
+import org.apache.druid.data.input.impl.StringInputRowParser;
+import org.apache.druid.data.input.impl.TimestampSpec;
+import org.apache.druid.java.util.common.DateTimes;
+import org.apache.druid.segment.incremental.IncrementalIndex;
+import org.apache.druid.segment.incremental.IncrementalIndexSchema;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MapVirtualColumnTestBase
+{
+  static IncrementalIndex generateIndex() throws IOException
+  {
+    final CharSource input = CharSource.wrap(
+        "2011-01-12T00:00:00.000Z\ta\tkey1,key2,key3\tvalue1,value2,value3\n" +
+        "2011-01-12T00:00:00.000Z\tb\tkey4,key5,key6\tvalue4\n" +
+        "2011-01-12T00:00:00.000Z\tc\tkey1,key5\tvalue1,value5,value9\n"
+    );
+
+    final StringInputRowParser parser = new StringInputRowParser(
+        new DelimitedParseSpec(
+            new TimestampSpec("ts", "auto", null),
+            new 
DimensionsSpec(DimensionsSpec.getDefaultSchemas(Arrays.asList("dim", "keys", 
"values")), null, null),
+            "\t",
+            ",",
+            Arrays.asList("ts", "dim", "keys", "values"),
+            false,
+            0
+        ),
+        "utf8"
+    );
+
+    final IncrementalIndexSchema schema = new IncrementalIndexSchema.Builder()
+        .withMinTimestamp(DateTimes.of("2011-01-12T00:00:00.000Z").getMillis())
+        .build();
+
+    return TestIndex.loadIncrementalIndex(
+        () -> new IncrementalIndex.Builder()
+            .setIndexSchema(schema)
+            .setMaxRowCount(10000)
+            .buildOnheap(),
+        input,
+        parser
+    );
+  }
+
+  static <K, V> Map<K, V> mapOf(Object... elements)
+  {
+    final Map<K, V> map = new HashMap<>();
+    for (int i = 0; i < elements.length; i += 2) {
+      //noinspection unchecked
+      map.put((K) elements[i], (V) elements[i + 1]);
+    }
+    return map;
+  }
+}
diff --git 
a/extensions-contrib/virtual-columns/src/test/java/org/apache/druid/segment/MapVirtualColumnTopNTest.java
 
b/extensions-contrib/virtual-columns/src/test/java/org/apache/druid/segment/MapVirtualColumnTopNTest.java
new file mode 100644
index 0000000..e223681
--- /dev/null
+++ 
b/extensions-contrib/virtual-columns/src/test/java/org/apache/druid/segment/MapVirtualColumnTopNTest.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.druid.segment;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.druid.collections.StupidPool;
+import org.apache.druid.java.util.common.DateTimes;
+import org.apache.druid.java.util.common.Intervals;
+import org.apache.druid.java.util.common.granularity.Granularities;
+import org.apache.druid.query.QueryPlus;
+import org.apache.druid.query.QueryRunner;
+import org.apache.druid.query.QueryRunnerTestHelper;
+import org.apache.druid.query.Result;
+import org.apache.druid.query.TableDataSource;
+import org.apache.druid.query.aggregation.CountAggregatorFactory;
+import org.apache.druid.query.dimension.DefaultDimensionSpec;
+import org.apache.druid.query.spec.MultipleIntervalSegmentSpec;
+import org.apache.druid.query.topn.DimensionAndMetricValueExtractor;
+import org.apache.druid.query.topn.NumericTopNMetricSpec;
+import org.apache.druid.query.topn.TopNQuery;
+import org.apache.druid.query.topn.TopNQueryConfig;
+import org.apache.druid.query.topn.TopNQueryQueryToolChest;
+import org.apache.druid.query.topn.TopNQueryRunnerFactory;
+import org.apache.druid.query.topn.TopNResultValue;
+import org.apache.druid.segment.incremental.IncrementalIndex;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+public class MapVirtualColumnTopNTest
+{
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  private QueryRunner<Result<TopNResultValue>> runner;
+
+  @Before
+  public void setup() throws IOException
+  {
+    final IncrementalIndex incrementalIndex = 
MapVirtualColumnTestBase.generateIndex();
+
+    final TopNQueryRunnerFactory factory = new TopNQueryRunnerFactory(
+        new StupidPool<>("map-virtual-column-test", () -> 
ByteBuffer.allocate(1024)),
+        new TopNQueryQueryToolChest(
+            new TopNQueryConfig(),
+            QueryRunnerTestHelper.NoopIntervalChunkingQueryRunnerDecorator()
+        ),
+        QueryRunnerTestHelper.NOOP_QUERYWATCHER
+    );
+
+    runner = QueryRunnerTestHelper.makeQueryRunner(
+        factory,
+        "index1",
+        new IncrementalIndexSegment(incrementalIndex, "index1"),
+        "incremental"
+    );
+  }
+
+  @Test
+  public void testWithMapColumn()
+  {
+    final TopNQuery query = new TopNQuery(
+        new TableDataSource(QueryRunnerTestHelper.dataSource),
+        VirtualColumns.create(
+            ImmutableList.of(
+                new MapVirtualColumn("keys", "values", "params")
+            )
+        ),
+        new DefaultDimensionSpec("params", "params"), // params is the map type
+        new NumericTopNMetricSpec("count"),
+        1,
+        new 
MultipleIntervalSegmentSpec(ImmutableList.of(Intervals.of("2011/2012"))),
+        null,
+        Granularities.ALL,
+        ImmutableList.of(new CountAggregatorFactory("count")),
+        null,
+        null
+    );
+
+    expectedException.expect(UnsupportedOperationException.class);
+    expectedException.expectMessage("Map column doesn't support getRow()");
+    runner.run(QueryPlus.wrap(query), new HashMap<>()).toList();
+  }
+
+  @Test
+  public void testWithSubColumn()
+  {
+    final TopNQuery query = new TopNQuery(
+        new TableDataSource(QueryRunnerTestHelper.dataSource),
+        VirtualColumns.create(
+            ImmutableList.of(
+                new MapVirtualColumn("keys", "values", "params")
+            )
+        ),
+        new DefaultDimensionSpec("params.key3", "params.key3"), // params.key3 
is string
+        new NumericTopNMetricSpec("count"),
+        2,
+        new 
MultipleIntervalSegmentSpec(ImmutableList.of(Intervals.of("2011/2012"))),
+        null,
+        Granularities.ALL,
+        ImmutableList.of(new CountAggregatorFactory("count")),
+        null,
+        null
+    );
+
+    final List<Result<TopNResultValue>> result = 
runner.run(QueryPlus.wrap(query), new HashMap<>()).toList();
+    final List<Result<TopNResultValue>> expected = Collections.singletonList(
+        new Result<>(
+            DateTimes.of("2011-01-12T00:00:00.000Z"),
+            new TopNResultValue(
+                ImmutableList.of(
+                    new 
DimensionAndMetricValueExtractor(MapVirtualColumnTestBase.mapOf("count", 2L, 
"params.key3", null)),
+                    new 
DimensionAndMetricValueExtractor(MapVirtualColumnTestBase.mapOf("count", 1L, 
"params.key3", "value3"))
+                )
+            )
+        )
+    );
+
+    Assert.assertEquals(expected, result);
+  }
+}
diff --git 
a/processing/src/test/java/org/apache/druid/query/groupby/GroupByQueryMergeBufferTest.java
 
b/processing/src/test/java/org/apache/druid/query/groupby/GroupByQueryMergeBufferTest.java
index 537ecb3..abcf40e 100644
--- 
a/processing/src/test/java/org/apache/druid/query/groupby/GroupByQueryMergeBufferTest.java
+++ 
b/processing/src/test/java/org/apache/druid/query/groupby/GroupByQueryMergeBufferTest.java
@@ -104,7 +104,6 @@ public class GroupByQueryMergeBufferTest
 
   public static final DruidProcessingConfig PROCESSING_CONFIG = new 
DruidProcessingConfig()
   {
-
     @Override
     public String getFormatString()
     {
diff --git a/processing/src/test/java/org/apache/druid/segment/TestIndex.java 
b/processing/src/test/java/org/apache/druid/segment/TestIndex.java
index 201354a..dd865fe 100644
--- a/processing/src/test/java/org/apache/druid/segment/TestIndex.java
+++ b/processing/src/test/java/org/apache/druid/segment/TestIndex.java
@@ -19,6 +19,7 @@
 
 package org.apache.druid.segment;
 
+import com.google.common.base.Supplier;
 import com.google.common.base.Throwables;
 import com.google.common.io.CharSource;
 import com.google.common.io.LineProcessor;
@@ -315,15 +316,16 @@ public class TestIndex
         ),
         "utf8"
     );
-    return loadIncrementalIndex(retVal, source, parser);
+    return loadIncrementalIndex(() -> retVal, source, parser);
   }
 
   public static IncrementalIndex loadIncrementalIndex(
-      final IncrementalIndex retVal,
+      final Supplier<IncrementalIndex> indexSupplier,
       final CharSource source,
       final StringInputRowParser parser
   ) throws IOException
   {
+    final IncrementalIndex retVal = indexSupplier.get();
     final AtomicLong startTime = new AtomicLong();
     int lineCount = source.readLines(
         new LineProcessor<Integer>()


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

Reply via email to