@Override public StreamProperties visitTopN(TopNNode node, List<StreamProperties> inputProperties) { // Partial TopN doesn't guarantee that stream is ordered if (node.getStep().equals(TopNNode.Step.PARTIAL)) { return Iterables.getOnlyElement(inputProperties); } return StreamProperties.ordered(); }
private boolean shouldBeDistributed(PlanNode planNode) { if (planNode instanceof JoinNode) { return true; } if (planNode instanceof AggregationNode) { // TODO: differentiate aggregation with empty grouping set return true; } if (planNode instanceof TopNNode) { return ((TopNNode) planNode).getStep() == TopNNode.Step.PARTIAL; } return false; }
@Override public PlanNode visitTopN(TopNNode node, RewriteContext<Set<Symbol>> context) { ImmutableSet.Builder<Symbol> expectedInputs = ImmutableSet.<Symbol>builder() .addAll(context.get()) .addAll(node.getOrderingScheme().getOrderBy()); PlanNode source = context.rewrite(node.getSource(), expectedInputs.build()); return new TopNNode(node.getId(), source, node.getCount(), node.getOrderingScheme(), node.getStep()); }
public TopNNode map(TopNNode node, PlanNode source, PlanNodeId newNodeId) { ImmutableList.Builder<Symbol> symbols = ImmutableList.builder(); ImmutableMap.Builder<Symbol, SortOrder> orderings = ImmutableMap.builder(); Set<Symbol> seenCanonicals = new HashSet<>(node.getOrderingScheme().getOrderBy().size()); for (Symbol symbol : node.getOrderingScheme().getOrderBy()) { Symbol canonical = map(symbol); if (seenCanonicals.add(canonical)) { seenCanonicals.add(canonical); symbols.add(canonical); orderings.put(canonical, node.getOrderingScheme().getOrdering(symbol)); } } return new TopNNode( newNodeId, source, node.getCount(), new OrderingScheme(symbols.build(), orderings.build()), node.getStep()); }
@Override public Void visitTopN(TopNNode node, Integer indent) { Iterable<String> keys = Iterables.transform(node.getOrderingScheme().getOrderBy(), input -> input + " " + node.getOrderingScheme().getOrdering(input)); print(indent, "- TopN%s[%s by (%s)] => [%s]", node.getStep() == TopNNode.Step.PARTIAL ? "Partial" : "", node.getCount(), Joiner.on(", ").join(keys), formatOutputs(node.getOutputSymbols())); printPlanNodesStatsAndCost(indent + 2, node); printStats(indent + 2, node.getId()); return processChildren(node, indent + 1); }
@Override public PlanWithProperties visitTopN(TopNNode node, PreferredProperties preferredProperties) { PlanWithProperties child; switch (node.getStep()) { case SINGLE: case FINAL: child = planChild(node, PreferredProperties.undistributed()); if (!child.getProperties().isSingleNode()) { child = withDerivedProperties( gatheringExchange(idAllocator.getNextId(), REMOTE, child.getNode()), child.getProperties()); } break; case PARTIAL: child = planChild(node, PreferredProperties.any()); break; default: throw new UnsupportedOperationException(format("Unsupported step for TopN [%s]", node.getStep())); } return rebaseAndDeriveProperties(node, child); }
@Override public PlanNode visitTopN(TopNNode node, RewriteContext<LimitContext> context) { LimitContext limit = context.get(); PlanNode rewrittenSource = context.rewrite(node.getSource()); if (rewrittenSource == node.getSource() && limit == null) { return node; } long count = node.getCount(); if (limit != null) { count = Math.min(count, limit.getCount()); } return new TopNNode(node.getId(), rewrittenSource, count, node.getOrderingScheme(), node.getStep()); }
@Override public PlanWithProperties visitTopN(TopNNode node, StreamPreferredProperties parentPreferences) { if (node.getStep().equals(TopNNode.Step.PARTIAL)) { return planAndEnforceChildren( node, parentPreferences.withoutPreference().withDefaultParallelism(session), parentPreferences.withDefaultParallelism(session)); } // final topN requires that all data be in one stream // also, a final changes the input organization completely, so we do not pass through parent preferences return planAndEnforceChildren( node, singleStream(), defaultParallelism(session)); }
@Test public void testUnionUnderTopN() { Plan plan = plan( "SELECT * FROM (" + " SELECT regionkey FROM nation " + " UNION ALL " + " SELECT nationkey FROM nation" + ") t(a) " + "ORDER BY a LIMIT 1", LogicalPlanner.Stage.OPTIMIZED_AND_VALIDATED, false); List<PlanNode> remotes = searchFrom(plan.getRoot()) .where(TestUnion::isRemoteExchange) .findAll(); assertEquals(remotes.size(), 1, "There should be exactly one RemoteExchange"); assertEquals(((ExchangeNode) Iterables.getOnlyElement(remotes)).getType(), GATHER); int numberOfpartialTopN = searchFrom(plan.getRoot()) .where(planNode -> planNode instanceof TopNNode && ((TopNNode) planNode).getStep().equals(TopNNode.Step.PARTIAL)) .count(); assertEquals(numberOfpartialTopN, 2, "There should be exactly two partial TopN nodes"); assertPlanIsFullyDistributed(plan); }