public List<Query> optimize(Query query)
  {
    long start = System.currentTimeMillis();
    // only topN/timeseries/groupby query can be optimized
    // only TableDataSource can be optimiezed
    if (!(query instanceof TopNQuery || query instanceof TimeseriesQuery || query instanceof GroupByQuery)
        || !(query.getDataSource() instanceof TableDataSource)) {
      return Collections.singletonList(query);
    }
    String datasourceName = ((TableDataSource) query.getDataSource()).getName();
    // get all derivatives for datasource in query. The derivatives set is sorted by average size of 
    // per segment granularity.
    Set<DerivativeDataSource> derivatives = DerivativeDataSourceManager.getDerivatives(datasourceName);
    
    if (derivatives.isEmpty()) {
      return Collections.singletonList(query);
    }
    lock.readLock().lock();
    try {
      totalCount.putIfAbsent(datasourceName, new AtomicLong(0));
      hitCount.putIfAbsent(datasourceName, new AtomicLong(0));
      costTime.putIfAbsent(datasourceName, new AtomicLong(0));
      totalCount.get(datasourceName).incrementAndGet();
      
      // get all fields which the query required
      Set<String> requiredFields = MaterializedViewUtils.getRequiredFields(query);
      
      Set<DerivativeDataSource> derivativesWithRequiredFields = new HashSet<>();
      for (DerivativeDataSource derivativeDataSource : derivatives) {
        derivativesHitCount.putIfAbsent(derivativeDataSource.getName(), new AtomicLong(0));
        if (derivativeDataSource.getColumns().containsAll(requiredFields)) {
          derivativesWithRequiredFields.add(derivativeDataSource);
        }
      }
      // if no derivatives contains all required dimensions, this materialized view selection failed.
      if (derivativesWithRequiredFields.isEmpty()) {
        missFields.putIfAbsent(datasourceName, new ConcurrentHashMap<>());
        missFields.get(datasourceName).putIfAbsent(requiredFields, new AtomicLong(0));
        missFields.get(datasourceName).get(requiredFields).incrementAndGet();
        costTime.get(datasourceName).addAndGet(System.currentTimeMillis() - start);
        return Collections.singletonList(query);
      }
      
      List<Query> queries = new ArrayList<>();
      List<Interval> remainingQueryIntervals = (List<Interval>) query.getIntervals();
      
      for (DerivativeDataSource derivativeDataSource : ImmutableSortedSet.copyOf(derivativesWithRequiredFields)) {
        final List<Interval> derivativeIntervals = remainingQueryIntervals.stream()
            .flatMap(interval -> serverView
                .getTimeline((new TableDataSource(derivativeDataSource.getName())))
                .lookup(interval)
                .stream()
                .map(TimelineObjectHolder::getInterval)
            )
            .collect(Collectors.toList());
        // if the derivative does not contain any parts of intervals in the query, the derivative will
        // not be selected. 
        if (derivativeIntervals.isEmpty()) {
          continue;
        }
        
        remainingQueryIntervals = MaterializedViewUtils.minus(remainingQueryIntervals, derivativeIntervals);
        queries.add(
            query.withDataSource(new TableDataSource(derivativeDataSource.getName()))
                .withQuerySegmentSpec(new MultipleIntervalSegmentSpec(derivativeIntervals))
        );
        derivativesHitCount.get(derivativeDataSource.getName()).incrementAndGet();
        if (remainingQueryIntervals.isEmpty()) {
          break;
        }
      }

      if (queries.isEmpty()) {
        costTime.get(datasourceName).addAndGet(System.currentTimeMillis() - start);
        return Collections.singletonList(query);
      }

      //after materialized view selection, the result of the remaining query interval will be computed based on
      // the original datasource. 
      if (!remainingQueryIntervals.isEmpty()) {
        queries.add(query.withQuerySegmentSpec(new MultipleIntervalSegmentSpec(remainingQueryIntervals)));
      }
      hitCount.get(datasourceName).incrementAndGet();
      costTime.get(datasourceName).addAndGet(System.currentTimeMillis() - start);
      return queries;
    } 
    finally {
      lock.readLock().unlock();
    }
  }
public List < Query > optimize ( Query query ) { long start = System . currentTimeMillis ( ) ; if ( ! ( query instanceof TopNQuery || query instanceof TimeseriesQuery || query instanceof GroupByQuery ) || ! ( query . getDataSource ( ) instanceof TableDataSource ) ) { return Collections . singletonList ( query ) ; } String datasourceName = ( ( TableDataSource ) query . getDataSource ( ) ) . getName ( ) ; Set < DerivativeDataSource > derivatives = DerivativeDataSourceManager . getDerivatives ( datasourceName ) ; if ( derivatives . isEmpty ( ) ) { return Collections . singletonList ( query ) ; } lock . readLock ( ) . lock ( ) ; try { totalCount . putIfAbsent ( datasourceName , new AtomicLong ( 0 ) ) ; hitCount . putIfAbsent ( datasourceName , new AtomicLong ( 0 ) ) ; costTime . putIfAbsent ( datasourceName , new AtomicLong ( 0 ) ) ; totalCount . get ( datasourceName ) . incrementAndGet ( ) ; Set < String > requiredFields = MaterializedViewUtils . getRequiredFields ( query ) ; Set < DerivativeDataSource > derivativesWithRequiredFields = new HashSet < > ( ) ; for ( DerivativeDataSource derivativeDataSource : derivatives ) { derivativesHitCount . putIfAbsent ( derivativeDataSource . getName ( ) , new AtomicLong ( 0 ) ) ; if ( derivativeDataSource . getColumns ( ) . containsAll ( requiredFields ) ) { derivativesWithRequiredFields . add ( derivativeDataSource ) ; } } if ( derivativesWithRequiredFields . isEmpty ( ) ) { missFields . putIfAbsent ( datasourceName , new ConcurrentHashMap < > ( ) ) ; missFields . get ( datasourceName ) . putIfAbsent ( requiredFields , new AtomicLong ( 0 ) ) ; missFields . get ( datasourceName ) . get ( requiredFields ) . incrementAndGet ( ) ; costTime . get ( datasourceName ) . addAndGet ( System . currentTimeMillis ( ) - start ) ; return Collections . singletonList ( query ) ; } List < Query > queries = new ArrayList < > ( ) ; List < Interval > remainingQueryIntervals = ( List < Interval > ) query . getIntervals ( ) ; for ( DerivativeDataSource derivativeDataSource : ImmutableSortedSet . copyOf ( derivativesWithRequiredFields ) ) { final List < Interval > derivativeIntervals = remainingQueryIntervals . stream ( ) . flatMap ( interval -> serverView . getTimeline ( ( new TableDataSource ( derivativeDataSource . getName ( ) ) ) ) . lookup ( interval ) . stream ( ) . map ( TimelineObjectHolder :: getInterval ) ) . collect ( Collectors . toList ( ) ) ; if ( derivativeIntervals . isEmpty ( ) ) { continue ; } remainingQueryIntervals = MaterializedViewUtils . minus ( remainingQueryIntervals , derivativeIntervals ) ; queries . add ( query . withDataSource ( new TableDataSource ( derivativeDataSource . getName ( ) ) ) . withQuerySegmentSpec ( new MultipleIntervalSegmentSpec ( derivativeIntervals ) ) ) ; derivativesHitCount . get ( derivativeDataSource . getName ( ) ) . incrementAndGet ( ) ; if ( remainingQueryIntervals . isEmpty ( ) ) { break ; } } if ( queries . isEmpty ( ) ) { costTime . get ( datasourceName ) . addAndGet ( System . currentTimeMillis ( ) - start ) ; return Collections . singletonList ( query ) ; } if ( ! remainingQueryIntervals . isEmpty ( ) ) { queries . add ( query . withQuerySegmentSpec ( new MultipleIntervalSegmentSpec ( remainingQueryIntervals ) ) ) ; } hitCount . get ( datasourceName ) . incrementAndGet ( ) ; costTime . get ( datasourceName ) . addAndGet ( System . currentTimeMillis ( ) - start ) ; return queries ; } finally { lock . readLock ( ) . unlock ( ) ; } }
Do main work about materialized view selection: transform user query to one or more sub-queries.

In the sub-query, the dataSource is the derivative of dataSource in user query, and sum of all sub-queries'
intervals equals the interval in user query

Derived dataSource with smallest average data size per segment granularity have highest priority to replace the
datasource in user query

@param query only TopNQuery/TimeseriesQuery/GroupByQuery can be optimized
@return a list of queries with specified derived dataSources and intervals