private static boolean canOptimizeWindowFunction(WindowNode node) { if (node.getWindowFunctions().size() != 1) { return false; } Symbol rowNumberSymbol = getOnlyElement(node.getWindowFunctions().entrySet()).getKey(); return isRowNumberSignature(node.getWindowFunctions().get(rowNumberSymbol).getSignature()); }
private static boolean canOptimizeWindowFunction(WindowNode node) { if (node.getWindowFunctions().size() != 1) { return false; } Symbol rowNumberSymbol = getOnlyElement(node.getWindowFunctions().entrySet()).getKey(); return isRowNumberSignature(node.getWindowFunctions().get(rowNumberSymbol).getSignature()); }
public static boolean dependsOn(WindowNode parent, WindowNode child) { return parent.getPartitionBy().stream().anyMatch(child.getCreatedSymbols()::contains) || (parent.getOrderingScheme().isPresent() && parent.getOrderingScheme().get().getOrderBy().stream().anyMatch(child.getCreatedSymbols()::contains)) || parent.getWindowFunctions().values().stream() .map(WindowNode.Function::getFunctionCall) .map(SymbolsExtractor::extractUnique) .flatMap(Collection::stream) .anyMatch(child.getCreatedSymbols()::contains); } }
public static boolean dependsOn(WindowNode parent, WindowNode child) { return parent.getPartitionBy().stream().anyMatch(child.getCreatedSymbols()::contains) || (parent.getOrderingScheme().isPresent() && parent.getOrderingScheme().get().getOrderBy().stream().anyMatch(child.getCreatedSymbols()::contains)) || parent.getWindowFunctions().values().stream() .map(WindowNode.Function::getFunctionCall) .map(SymbolsExtractor::extractUnique) .flatMap(Collection::stream) .anyMatch(child.getCreatedSymbols()::contains); } }
@Override public Void visitWindow(WindowNode node, Void context) { visitPlan(node, context); checkWindowFunctions(node.getWindowFunctions()); return null; }
@Override public Void visitWindow(WindowNode node, Void context) { visitPlan(node, context); checkWindowFunctions(node.getWindowFunctions()); return null; }
@Override public PlanNode visitWindow(WindowNode node, RewriteContext<Void> context) { checkState(node.getWindowFunctions().size() == 1, "WindowFilterPushdown requires that WindowNodes contain exactly one window function"); PlanNode rewrittenSource = context.rewrite(node.getSource()); if (canReplaceWithRowNumber(node)) { return new RowNumberNode(idAllocator.getNextId(), rewrittenSource, node.getPartitionBy(), getOnlyElement(node.getWindowFunctions().keySet()), Optional.empty(), Optional.empty()); } return replaceChildren(node, ImmutableList.of(rewrittenSource)); }
private TopNRowNumberNode convertToTopNRowNumber(WindowNode windowNode, int limit) { return new TopNRowNumberNode(idAllocator.getNextId(), windowNode.getSource(), windowNode.getSpecification(), getOnlyElement(windowNode.getWindowFunctions().keySet()), limit, false, Optional.empty()); }
private TopNRowNumberNode convertToTopNRowNumber(WindowNode windowNode, int limit) { return new TopNRowNumberNode(idAllocator.getNextId(), windowNode.getSource(), windowNode.getSpecification(), getOnlyElement(windowNode.getWindowFunctions().keySet()), limit, false, Optional.empty()); }
@Override public PlanNode visitWindow(WindowNode node, RewriteContext<Void> context) { checkState(node.getWindowFunctions().size() == 1, "WindowFilterPushdown requires that WindowNodes contain exactly one window function"); PlanNode rewrittenSource = context.rewrite(node.getSource()); if (canReplaceWithRowNumber(node)) { return new RowNumberNode(idAllocator.getNextId(), rewrittenSource, node.getPartitionBy(), getOnlyElement(node.getWindowFunctions().keySet()), Optional.empty(), Optional.empty()); } return replaceChildren(node, ImmutableList.of(rewrittenSource)); }
@Override protected Optional<PlanNode> manipulateAdjacentWindowNodes(WindowNode parent, WindowNode child, Context context) { if (!child.getSpecification().equals(parent.getSpecification()) || dependsOn(parent, child)) { return Optional.empty(); } ImmutableMap.Builder<Symbol, WindowNode.Function> functionsBuilder = ImmutableMap.builder(); functionsBuilder.putAll(parent.getWindowFunctions()); functionsBuilder.putAll(child.getWindowFunctions()); WindowNode mergedWindowNode = new WindowNode( parent.getId(), child.getSource(), parent.getSpecification(), functionsBuilder.build(), parent.getHashSymbol(), parent.getPrePartitionedInputs(), parent.getPreSortedOrderPrefix()); return Optional.of( restrictOutputs(context.getIdAllocator(), mergedWindowNode, ImmutableSet.copyOf(parent.getOutputSymbols())) .orElse(mergedWindowNode)); } }
@Override protected Optional<PlanNode> manipulateAdjacentWindowNodes(WindowNode parent, WindowNode child, Context context) { if (!child.getSpecification().equals(parent.getSpecification()) || dependsOn(parent, child)) { return Optional.empty(); } ImmutableMap.Builder<Symbol, WindowNode.Function> functionsBuilder = ImmutableMap.builder(); functionsBuilder.putAll(parent.getWindowFunctions()); functionsBuilder.putAll(child.getWindowFunctions()); WindowNode mergedWindowNode = new WindowNode( parent.getId(), child.getSource(), parent.getSpecification(), functionsBuilder.build(), parent.getHashSymbol(), parent.getPrePartitionedInputs(), parent.getPreSortedOrderPrefix()); return Optional.of( restrictOutputs(context.getIdAllocator(), mergedWindowNode, ImmutableSet.copyOf(parent.getOutputSymbols())) .orElse(mergedWindowNode)); } }
@Override public PlanNode visitFilter(FilterNode node, RewriteContext<Void> context) { PlanNode source = context.rewrite(node.getSource()); TupleDomain<Symbol> tupleDomain = fromPredicate(metadata, session, node.getPredicate(), types).getTupleDomain(); if (source instanceof RowNumberNode) { Symbol rowNumberSymbol = ((RowNumberNode) source).getRowNumberSymbol(); OptionalInt upperBound = extractUpperBound(tupleDomain, rowNumberSymbol); if (upperBound.isPresent()) { source = mergeLimit(((RowNumberNode) source), upperBound.getAsInt()); return rewriteFilterSource(node, source, rowNumberSymbol, upperBound.getAsInt()); } } else if (source instanceof WindowNode && canOptimizeWindowFunction((WindowNode) source) && isOptimizeTopNRowNumber(session)) { WindowNode windowNode = (WindowNode) source; Symbol rowNumberSymbol = getOnlyElement(windowNode.getWindowFunctions().entrySet()).getKey(); OptionalInt upperBound = extractUpperBound(tupleDomain, rowNumberSymbol); if (upperBound.isPresent()) { source = convertToTopNRowNumber(windowNode, upperBound.getAsInt()); return rewriteFilterSource(node, source, rowNumberSymbol, upperBound.getAsInt()); } } return replaceChildren(node, ImmutableList.of(source)); }
@Override public PlanNode visitFilter(FilterNode node, RewriteContext<Void> context) { PlanNode source = context.rewrite(node.getSource()); TupleDomain<Symbol> tupleDomain = fromPredicate(metadata, session, node.getPredicate(), types).getTupleDomain(); if (source instanceof RowNumberNode) { Symbol rowNumberSymbol = ((RowNumberNode) source).getRowNumberSymbol(); OptionalInt upperBound = extractUpperBound(tupleDomain, rowNumberSymbol); if (upperBound.isPresent()) { source = mergeLimit(((RowNumberNode) source), upperBound.getAsInt()); return rewriteFilterSource(node, source, rowNumberSymbol, upperBound.getAsInt()); } } else if (source instanceof WindowNode && canOptimizeWindowFunction((WindowNode) source) && isOptimizeTopNRowNumber(session)) { WindowNode windowNode = (WindowNode) source; Symbol rowNumberSymbol = getOnlyElement(windowNode.getWindowFunctions().entrySet()).getKey(); OptionalInt upperBound = extractUpperBound(tupleDomain, rowNumberSymbol); if (upperBound.isPresent()) { source = convertToTopNRowNumber(windowNode, upperBound.getAsInt()); return rewriteFilterSource(node, source, rowNumberSymbol, upperBound.getAsInt()); } } return replaceChildren(node, ImmutableList.of(source)); }
@Override public Optional<Symbol> getAssignedSymbol(PlanNode node, Session session, Metadata metadata, SymbolAliases symbolAliases) { Optional<Symbol> result = Optional.empty(); if (!(node instanceof WindowNode)) { return result; } WindowNode windowNode = (WindowNode) node; FunctionCall expectedCall = callMaker.getExpectedValue(symbolAliases); Optional<WindowNode.Frame> expectedFrame = frameMaker.map(maker -> maker.getExpectedValue(symbolAliases)); List<Symbol> matchedOutputs = windowNode.getWindowFunctions().entrySet().stream() .filter(assignment -> expectedCall.equals(assignment.getValue().getFunctionCall()) && signature.map(assignment.getValue().getSignature()::equals).orElse(true) && expectedFrame.map(assignment.getValue().getFrame()::equals).orElse(true)) .map(Map.Entry::getKey) .collect(toImmutableList()); checkState(matchedOutputs.size() <= 1, "Ambiguous function calls in %s", windowNode); if (matchedOutputs.isEmpty()) { return Optional.empty(); } return Optional.of(matchedOutputs.get(0)); }
@Override public Optional<Symbol> getAssignedSymbol(PlanNode node, Session session, Metadata metadata, SymbolAliases symbolAliases) { Optional<Symbol> result = Optional.empty(); if (!(node instanceof WindowNode)) { return result; } WindowNode windowNode = (WindowNode) node; FunctionCall expectedCall = callMaker.getExpectedValue(symbolAliases); Optional<WindowNode.Frame> expectedFrame = frameMaker.map(maker -> maker.getExpectedValue(symbolAliases)); List<Symbol> matchedOutputs = windowNode.getWindowFunctions().entrySet().stream() .filter(assignment -> expectedCall.equals(assignment.getValue().getFunctionCall()) && signature.map(assignment.getValue().getSignature()::equals).orElse(true) && expectedFrame.map(assignment.getValue().getFrame()::equals).orElse(true)) .map(Map.Entry::getKey) .collect(toImmutableList()); checkState(matchedOutputs.size() <= 1, "Ambiguous function calls in %s", windowNode); if (matchedOutputs.isEmpty()) { return Optional.empty(); } return Optional.of(matchedOutputs.get(0)); }
@Override public PlanNode visitWindow(WindowNode node, RewriteContext<Void> context) { PlanNode source = context.rewrite(node.getSource()); ImmutableMap.Builder<Symbol, WindowNode.Function> functions = ImmutableMap.builder(); for (Map.Entry<Symbol, WindowNode.Function> entry : node.getWindowFunctions().entrySet()) { Symbol symbol = entry.getKey(); FunctionCall canonicalFunctionCall = (FunctionCall) canonicalize(entry.getValue().getFunctionCall()); Signature signature = entry.getValue().getSignature(); WindowNode.Frame canonicalFrame = canonicalize(entry.getValue().getFrame()); functions.put(canonicalize(symbol), new WindowNode.Function(canonicalFunctionCall, signature, canonicalFrame)); } return new WindowNode( node.getId(), source, canonicalizeAndDistinct(node.getSpecification()), functions.build(), canonicalize(node.getHashSymbol()), canonicalize(node.getPrePartitionedInputs()), node.getPreSortedOrderPrefix()); }
@Override public PlanNode visitWindow(WindowNode node, RewriteContext<Void> context) { PlanNode source = context.rewrite(node.getSource()); ImmutableMap.Builder<Symbol, WindowNode.Function> functions = ImmutableMap.builder(); for (Map.Entry<Symbol, WindowNode.Function> entry : node.getWindowFunctions().entrySet()) { Symbol symbol = entry.getKey(); FunctionCall canonicalFunctionCall = (FunctionCall) canonicalize(entry.getValue().getFunctionCall()); Signature signature = entry.getValue().getSignature(); WindowNode.Frame canonicalFrame = canonicalize(entry.getValue().getFrame()); functions.put(canonicalize(symbol), new WindowNode.Function(canonicalFunctionCall, signature, canonicalFrame)); } return new WindowNode( node.getId(), source, canonicalizeAndDistinct(node.getSpecification()), functions.build(), canonicalize(node.getHashSymbol()), canonicalize(node.getPrePartitionedInputs()), node.getPreSortedOrderPrefix()); }
@Override public PlanWithProperties visitWindow(WindowNode node, HashComputationSet parentPreference) { if (node.getPartitionBy().isEmpty()) { return planSimpleNodeWithProperties(node, parentPreference, true); } Optional<HashComputation> hashComputation = computeHash(node.getPartitionBy()); PlanWithProperties child = planAndEnforce( node.getSource(), new HashComputationSet(hashComputation), true, parentPreference.withHashComputation(node, hashComputation)); Symbol hashSymbol = child.getRequiredHashSymbol(hashComputation.get()); return new PlanWithProperties( new WindowNode( node.getId(), child.getNode(), node.getSpecification(), node.getWindowFunctions(), Optional.of(hashSymbol), node.getPrePartitionedInputs(), node.getPreSortedOrderPrefix()), child.getHashSymbols()); }
@Override public PlanWithProperties visitWindow(WindowNode node, HashComputationSet parentPreference) { if (node.getPartitionBy().isEmpty()) { return planSimpleNodeWithProperties(node, parentPreference, true); } Optional<HashComputation> hashComputation = computeHash(node.getPartitionBy()); PlanWithProperties child = planAndEnforce( node.getSource(), new HashComputationSet(hashComputation), true, parentPreference.withHashComputation(node, hashComputation)); Symbol hashSymbol = child.getRequiredHashSymbol(hashComputation.get()); return new PlanWithProperties( new WindowNode( node.getId(), child.getNode(), node.getSpecification(), node.getWindowFunctions(), Optional.of(hashSymbol), node.getPrePartitionedInputs(), node.getPreSortedOrderPrefix()), child.getHashSymbols()); }