All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.druid.query.search.AutoStrategy Maven / Gradle / Ivy

/*
 * Licensed to Metamarkets Group Inc. (Metamarkets) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. Metamarkets 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 io.druid.query.search;

import com.metamx.emitter.EmittingLogger;
import io.druid.query.dimension.DimensionSpec;
import io.druid.query.filter.BitmapIndexSelector;
import io.druid.segment.ColumnSelectorBitmapIndexSelector;
import io.druid.segment.QueryableIndex;
import io.druid.segment.Segment;
import io.druid.segment.VirtualColumns;
import io.druid.segment.column.BitmapIndex;
import io.druid.segment.column.Column;

import java.util.List;

public class AutoStrategy extends SearchStrategy
{
  public static final String NAME = "auto";

  private static final EmittingLogger log = new EmittingLogger(AutoStrategy.class);

  public static AutoStrategy of(SearchQuery query)
  {
    return new AutoStrategy(query);
  }

  private AutoStrategy(SearchQuery query)
  {
    super(query);
  }

  @Override
  public List getExecutionPlan(SearchQuery query, Segment segment)
  {
    final QueryableIndex index = segment.asQueryableIndex();

    if (index != null) {
      final BitmapIndexSelector selector = new ColumnSelectorBitmapIndexSelector(
          index.getBitmapFactoryForDimensions(),
          VirtualColumns.EMPTY,
          index
      );

      // Index-only plan is used only when any filter is not specified or the filter supports bitmap indexes.
      //
      // Note: if some filters support bitmap indexes but others are not, the current implementation always employs
      // the cursor-based plan. This can be more optimized. One possible optimization is generating a bitmap index
      // from the non-bitmap-support filters, and then use it to compute the filtered result by intersecting bitmaps.
      if (filter == null || filter.supportsSelectivityEstimation(index, selector)) {
        final List dimsToSearch = getDimsToSearch(
            index.getAvailableDimensions(),
            query.getDimensions()
        );

        // Choose a search query execution strategy depending on the query.
        // The costs of index-only plan and cursor-based plan can be computed like below.
        //
        // c_index = (total cardinality of all search dimensions) * (bitmap intersection cost)
        //            * (search predicate processing cost)
        // c_cursor = (# of rows in a segment) * (filter selectivity) * (# of dimensions)
        //            * (search predicate processing cost)
        final SearchQueryDecisionHelper helper = getDecisionHelper(index);
        final double useIndexStrategyCost = helper.getBitmapIntersectCost() * computeTotalCard(index, dimsToSearch);
        final double cursorOnlyStrategyCost = (filter == null ? 1. : filter.estimateSelectivity(selector))
                                              * selector.getNumRows()
                                              * dimsToSearch.size();

        log.debug(
            "Use-index strategy cost: %f, cursor-only strategy cost: %f",
            useIndexStrategyCost,
            cursorOnlyStrategyCost
        );

        if (useIndexStrategyCost < cursorOnlyStrategyCost) {
          log.debug("Use-index execution strategy is selected, query id [%s]", query.getId());
          return UseIndexesStrategy.of(query).getExecutionPlan(query, segment);
        } else {
          log.debug("Cursor-only execution strategy is selected, query id [%s]", query.getId());
          return CursorOnlyStrategy.of(query).getExecutionPlan(query, segment);
        }
      } else {
        log.debug(
            "Filter doesn't support bitmap index. Fall back to cursor-only execution strategy, query id [%s]",
            query.getId()
        );
        return CursorOnlyStrategy.of(query).getExecutionPlan(query, segment);
      }

    } else {
      log.debug("Index doesn't exist. Fall back to cursor-only execution strategy, query id [%s]", query.getId());
      return CursorOnlyStrategy.of(query).getExecutionPlan(query, segment);
    }
  }

  private static long computeTotalCard(final QueryableIndex index, final Iterable dimensionSpecs)
  {
    long totalCard = 0;
    for (DimensionSpec dimension : dimensionSpecs) {
      final Column column = index.getColumn(dimension.getDimension());
      if (column != null) {
        final BitmapIndex bitmapIndex = column.getBitmapIndex();
        if (bitmapIndex != null) {
          totalCard += bitmapIndex.getCardinality();
        }
      }
    }
    return totalCard;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy