Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Licensed 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 com.facebook.presto.sql.planner.optimizations;
 
 
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import static com.google.common.base.Preconditions.checkNotNull;

Converts cardinality-insensitive aggregations (max, min, "distinct") over partition keys into simple metadata queries
 
 public class MetadataQueryOptimizer
         extends PlanOptimizer
 {
     private static final Set<StringALLOWED_FUNCTIONS = ImmutableSet.of("max""min""approx_distinct");
 
     private final Metadata metadata;
     private final SplitManager splitManager;
 
     public MetadataQueryOptimizer(Metadata metadataSplitManager splitManager)
     {
         checkNotNull(metadata"metadata is null");
         checkNotNull(splitManager"splitManager is null");
 
         this. = metadata;
         this. = splitManager;
     }
 
     @Override
     public PlanNode optimize(PlanNode planSession sessionMap<SymbolTypetypesSymbolAllocator symbolAllocatorPlanNodeIdAllocator idAllocator)
     {
         return PlanRewriter.rewriteWith(new Optimizer(idAllocator), plannull);
     }
 
     private static class Optimizer
             extends PlanRewriter<Void>
     {
         private final PlanNodeIdAllocator idAllocator;
         private final Metadata metadata;
         private final SplitManager splitManager;
 
         private Optimizer(Metadata metadataSplitManager splitManagerPlanNodeIdAllocator idAllocator)
         {
             this. = metadata;
             this. = splitManager;
             this. = idAllocator;
         }
 
         @Override
         public PlanNode visitAggregation(AggregationNode nodeRewriteContext<Voidcontext)
         {
             // supported functions are only MIN/MAX/APPROX_DISTINCT or distinct aggregates
             for (FunctionCall call : node.getAggregations().values()) {
                if (!.contains(call.getName().toString()) && !call.isDistinct()) {
                    return null;
                }
            }
            Optional<TableScanNoderesult = findTableScan(node.getSource());
            if (!result.isPresent()) {
                return null;
            }
            // verify all outputs of table scan are partition keys
            TableScanNode tableScan = result.get();
            ImmutableMap.Builder<SymbolTypetypesBuilder = ImmutableMap.builder();
            ImmutableMap.Builder<SymbolColumnHandlecolumnBuilder = ImmutableMap.builder();
            List<Symbolinputs = tableScan.getOutputSymbols();
            for (Symbol symbol : inputs) {
                ColumnHandle column = tableScan.getAssignments().get(symbol);
                ColumnMetadata columnMetadata = .getColumnMetadata(tableScan.getTable(), column);
                if (!columnMetadata.isPartitionKey()) {
                    // the optimization is only valid if the aggregation node only
                    // relies on partition keys
                    return null;
                }
                typesBuilder.put(symbolcolumnMetadata.getType());
                columnBuilder.put(symbolcolumn);
            }
            Map<SymbolColumnHandlecolumns = columnBuilder.build();
            Map<SymbolTypetypes = typesBuilder.build();
            // Materialize the list of partitions and replace the TableScan node
            // with a Values node
            List<Partitionpartitions;
            if (tableScan.getGeneratedPartitions().isPresent()) {
                partitions = tableScan.getGeneratedPartitions().get().getPartitions();
            }
            else {
                partitions = .getPartitions(result.get().getTable(), Optional.of(tableScan.getPartitionsDomainSummary()))
                        .getPartitions();
            }
            ImmutableList.Builder<List<Expression>> rowsBuilder = ImmutableList.builder();
            for (Partition partition : partitions) {
                Map<ColumnHandleSerializableNativeValueentries = partition.getTupleDomain().extractNullableFixedValues();
                ImmutableList.Builder<ExpressionrowBuilder = ImmutableList.builder();
                // for each input column, add a literal expression using the entry value
                for (Symbol input : inputs) {
                    ColumnHandle column = columns.get(input);
                    Type type = types.get(input);
                    SerializableNativeValue value = entries.get(column);
                    if (value == null) {
                        // partition key does not have a single value, so bail out to be safe
                        return null;
                    }
                    else {
                        rowBuilder.add(LiteralInterpreter.toExpression(value.getValue(), type));
                    }
                }
                rowsBuilder.add(rowBuilder.build());
            }
            // replace the tablescan node with a values node
            ValuesNode valuesNode = new ValuesNode(.getNextId(), inputsrowsBuilder.build());
            return PlanRewriter.rewriteWith(new Replacer(valuesNode), node);
        }
        private Optional<TableScanNodefindTableScan(PlanNode source)
        {
            while (true) {
                // allow any chain of linear transformations
                if (source instanceof MarkDistinctNode ||
                        source instanceof FilterNode ||
                        source instanceof LimitNode ||
                        source instanceof TopNNode ||
                        source instanceof SortNode) {
                    source = source.getSources().get(0);
                }
                else if (source instanceof ProjectNode) {
                    // verify projections are deterministic
                    ProjectNode project = (ProjectNodesource;
                    if (!Iterables.all(project.getExpressions(), DeterminismEvaluator::isDeterministic)) {
                        return Optional.empty();
                    }
                    source = project.getSource();
                }
                else if (source instanceof TableScanNode) {
                    return Optional.of((TableScanNodesource);
                }
                else {
                    return Optional.empty();
                }
            }
        }
    }
    private static class Replacer
            extends PlanRewriter<Void>
    {
        private final ValuesNode replacement;
        private Replacer(ValuesNode replacement)
        {
            this. = replacement;
        }
        @Override
        public PlanNode visitTableScan(TableScanNode nodeRewriteContext<Voidcontext)
        {
            return ;
        }
    }
New to GrepCode? Check out our FAQ X