@Nullable
  public TopNQuery toTopNQuery()
  {
    // Must have GROUP BY one column, ORDER BY zero or one column, limit less than maxTopNLimit, and no HAVING.
    final boolean topNOk = grouping != null
                           && grouping.getDimensions().size() == 1
                           && limitSpec != null
                           && (limitSpec.getColumns().size() <= 1
                               && limitSpec.getLimit() <= plannerContext.getPlannerConfig().getMaxTopNLimit())
                           && grouping.getHavingFilter() == null;

    if (!topNOk) {
      return null;
    }

    final DimensionSpec dimensionSpec = Iterables.getOnlyElement(grouping.getDimensions()).toDimensionSpec();
    final OrderByColumnSpec limitColumn;
    if (limitSpec.getColumns().isEmpty()) {
      limitColumn = new OrderByColumnSpec(
          dimensionSpec.getOutputName(),
          OrderByColumnSpec.Direction.ASCENDING,
          Calcites.getStringComparatorForValueType(dimensionSpec.getOutputType())
      );
    } else {
      limitColumn = Iterables.getOnlyElement(limitSpec.getColumns());
    }
    final TopNMetricSpec topNMetricSpec;

    if (limitColumn.getDimension().equals(dimensionSpec.getOutputName())) {
      // DimensionTopNMetricSpec is exact; always return it even if allowApproximate is false.
      final DimensionTopNMetricSpec baseMetricSpec = new DimensionTopNMetricSpec(
          null,
          limitColumn.getDimensionComparator()
      );
      topNMetricSpec = limitColumn.getDirection() == OrderByColumnSpec.Direction.ASCENDING
                       ? baseMetricSpec
                       : new InvertedTopNMetricSpec(baseMetricSpec);
    } else if (plannerContext.getPlannerConfig().isUseApproximateTopN()) {
      // ORDER BY metric
      final NumericTopNMetricSpec baseMetricSpec = new NumericTopNMetricSpec(limitColumn.getDimension());
      topNMetricSpec = limitColumn.getDirection() == OrderByColumnSpec.Direction.ASCENDING
                       ? new InvertedTopNMetricSpec(baseMetricSpec)
                       : baseMetricSpec;
    } else {
      return null;
    }

    final Filtration filtration = Filtration.create(filter).optimize(sourceQuerySignature);

    final List<PostAggregator> postAggregators = new ArrayList<>(grouping.getPostAggregators());
    if (sortProject != null) {
      postAggregators.addAll(sortProject.getPostAggregators());
    }

    return new TopNQuery(
        dataSource,
        getVirtualColumns(true),
        dimensionSpec,
        topNMetricSpec,
        limitSpec.getLimit(),
        filtration.getQuerySegmentSpec(),
        filtration.getDimFilter(),
        Granularities.ALL,
        grouping.getAggregatorFactories(),
        postAggregators,
        ImmutableSortedMap.copyOf(plannerContext.getQueryContext())
    );
  }
@ Nullable public TopNQuery toTopNQuery ( ) { final boolean topNOk = grouping != null && grouping . getDimensions ( ) . size ( ) == 1 && limitSpec != null && ( limitSpec . getColumns ( ) . size ( ) <= 1 && limitSpec . getLimit ( ) <= plannerContext . getPlannerConfig ( ) . getMaxTopNLimit ( ) ) && grouping . getHavingFilter ( ) == null ; if ( ! topNOk ) { return null ; } final DimensionSpec dimensionSpec = Iterables . getOnlyElement ( grouping . getDimensions ( ) ) . toDimensionSpec ( ) ; final OrderByColumnSpec limitColumn ; if ( limitSpec . getColumns ( ) . isEmpty ( ) ) { limitColumn = new OrderByColumnSpec ( dimensionSpec . getOutputName ( ) , OrderByColumnSpec . Direction . ASCENDING , Calcites . getStringComparatorForValueType ( dimensionSpec . getOutputType ( ) ) ) ; } else { limitColumn = Iterables . getOnlyElement ( limitSpec . getColumns ( ) ) ; } final TopNMetricSpec topNMetricSpec ; if ( limitColumn . getDimension ( ) . equals ( dimensionSpec . getOutputName ( ) ) ) { final DimensionTopNMetricSpec baseMetricSpec = new DimensionTopNMetricSpec ( null , limitColumn . getDimensionComparator ( ) ) ; topNMetricSpec = limitColumn . getDirection ( ) == OrderByColumnSpec . Direction . ASCENDING ? baseMetricSpec : new InvertedTopNMetricSpec ( baseMetricSpec ) ; } else if ( plannerContext . getPlannerConfig ( ) . isUseApproximateTopN ( ) ) { final NumericTopNMetricSpec baseMetricSpec = new NumericTopNMetricSpec ( limitColumn . getDimension ( ) ) ; topNMetricSpec = limitColumn . getDirection ( ) == OrderByColumnSpec . Direction . ASCENDING ? new InvertedTopNMetricSpec ( baseMetricSpec ) : baseMetricSpec ; } else { return null ; } final Filtration filtration = Filtration . create ( filter ) . optimize ( sourceQuerySignature ) ; final List < PostAggregator > postAggregators = new ArrayList < > ( grouping . getPostAggregators ( ) ) ; if ( sortProject != null ) { postAggregators . addAll ( sortProject . getPostAggregators ( ) ) ; } return new TopNQuery ( dataSource , getVirtualColumns ( true ) , dimensionSpec , topNMetricSpec , limitSpec . getLimit ( ) , filtration . getQuerySegmentSpec ( ) , filtration . getDimFilter ( ) , Granularities . ALL , grouping . getAggregatorFactories ( ) , postAggregators , ImmutableSortedMap . copyOf ( plannerContext . getQueryContext ( ) ) ) ; }
Return this query as a TopN query, or null if this query is not compatible with TopN.

@return query or null