@Override public Map<PlanNodeId, SplitSource> visitJoin(JoinNode node, Void context) { Map<PlanNodeId, SplitSource> leftSplits = node.getLeft().accept(this, context); Map<PlanNodeId, SplitSource> rightSplits = node.getRight().accept(this, context); return ImmutableMap.<PlanNodeId, SplitSource>builder() .putAll(leftSplits) .putAll(rightSplits) .build(); }
@Override public PhysicalOperation visitJoin(JoinNode node, LocalExecutionPlanContext context) { if (node.isCrossJoin()) { return createNestedLoopJoin(node, context); } List<JoinNode.EquiJoinClause> clauses = node.getCriteria(); List<Symbol> leftSymbols = Lists.transform(clauses, JoinNode.EquiJoinClause::getLeft); List<Symbol> rightSymbols = Lists.transform(clauses, JoinNode.EquiJoinClause::getRight); switch (node.getType()) { case INNER: case LEFT: case RIGHT: case FULL: return createLookupJoin(node, node.getLeft(), leftSymbols, node.getLeftHashSymbol(), node.getRight(), rightSymbols, node.getRightHashSymbol(), context); default: throw new UnsupportedOperationException("Unsupported join type: " + node.getType()); } }
@Override public PlanNodeCostEstimate visitJoin(JoinNode node, Void context) { return calculateJoinExchangeCost( node.getLeft(), node.getRight(), stats, types, Objects.equals(node.getDistributionType(), Optional.of(JoinNode.DistributionType.REPLICATED)), taskCountEstimator.estimateSourceDistributedTaskCount()); }
@Override protected Optional<PlanNode> pushDownProjectOff(PlanNodeIdAllocator idAllocator, JoinNode joinNode, Set<Symbol> referencedOutputs) { return Optional.of( new JoinNode( joinNode.getId(), joinNode.getType(), joinNode.getLeft(), joinNode.getRight(), joinNode.getCriteria(), filteredCopy(joinNode.getOutputSymbols(), referencedOutputs::contains), joinNode.getFilter(), joinNode.getLeftHashSymbol(), joinNode.getRightHashSymbol(), joinNode.getDistributionType())); } }
@Override public Set<PlanFragmentId> visitJoin(JoinNode node, PlanFragmentId currentFragmentId) { return processJoin(node.getRight(), node.getLeft(), currentFragmentId); }
@Override public PlanNode visitJoin(JoinNode node, RewriteContext<Void> context) { PlanNode left = context.rewrite(node.getLeft()); PlanNode right = context.rewrite(node.getRight()); List<JoinNode.EquiJoinClause> canonicalCriteria = canonicalizeJoinCriteria(node.getCriteria()); Optional<Expression> canonicalFilter = node.getFilter().map(this::canonicalize); Optional<Symbol> canonicalLeftHashSymbol = canonicalize(node.getLeftHashSymbol()); Optional<Symbol> canonicalRightHashSymbol = canonicalize(node.getRightHashSymbol()); if (node.getType().equals(INNER)) { canonicalCriteria.stream() .filter(clause -> types.get(clause.getLeft()).equals(types.get(clause.getRight()))) .filter(clause -> node.getOutputSymbols().contains(clause.getLeft())) .forEach(clause -> map(clause.getRight(), clause.getLeft())); } return new JoinNode(node.getId(), node.getType(), left, right, canonicalCriteria, canonicalizeAndDistinct(node.getOutputSymbols()), canonicalFilter, canonicalLeftHashSymbol, canonicalRightHashSymbol, node.getDistributionType()); }
@Override public PlanNodeCostEstimate visitJoin(JoinNode node, Void context) { return calculateJoinCost( node, node.getLeft(), node.getRight(), Objects.equals(node.getDistributionType(), Optional.of(JoinNode.DistributionType.REPLICATED))); }
private PlanNode pushPartialToLeftChild(AggregationNode node, JoinNode child, Context context) { Set<Symbol> joinLeftChildSymbols = ImmutableSet.copyOf(child.getLeft().getOutputSymbols()); List<Symbol> groupingSet = getPushedDownGroupingSet(node, joinLeftChildSymbols, intersection(getJoinRequiredSymbols(child), joinLeftChildSymbols)); AggregationNode pushedAggregation = replaceAggregationSource(node, child.getLeft(), groupingSet); return pushPartialToJoin(node, child, pushedAggregation, child.getRight(), context); }
private PlanWithProperties planPartitionedJoin(JoinNode node, List<Symbol> leftSymbols, List<Symbol> rightSymbols) { return planPartitionedJoin(node, leftSymbols, rightSymbols, node.getLeft().accept(this, PreferredProperties.partitioned(ImmutableSet.copyOf(leftSymbols)))); }
@Override public Void visitJoin(JoinNode node, Void context) { node.getRight().accept(this, context); node.getLeft().accept(this, context); return null; }
@Override public Void visitJoin(JoinNode node, Consumer<PlanNodeId> schedulingOrder) { node.getRight().accept(this, schedulingOrder); node.getLeft().accept(this, schedulingOrder); return null; }
@Override public Void visitJoin(JoinNode node, Void context) { List<Expression> joinExpressions = new ArrayList<>(); for (JoinNode.EquiJoinClause clause : node.getCriteria()) { joinExpressions.add(clause.toExpression()); } String criteria = Joiner.on(" AND ").join(joinExpressions); printNode(node, node.getType().getJoinLabel(), criteria, NODE_COLORS.get(NodeType.JOIN)); node.getLeft().accept(this, context); node.getRight().accept(this, context); return null; }
private static PlanNode getOuterTable(JoinNode join) { checkState(join.getType() == JoinNode.Type.LEFT || join.getType() == JoinNode.Type.RIGHT, "expected LEFT or RIGHT JOIN"); PlanNode outerNode; if (join.getType().equals(JoinNode.Type.LEFT)) { outerNode = join.getLeft(); } else { outerNode = join.getRight(); } return outerNode; }
private static PlanNode getInnerTable(JoinNode join) { checkState(join.getType() == JoinNode.Type.LEFT || join.getType() == JoinNode.Type.RIGHT, "expected LEFT or RIGHT JOIN"); PlanNode innerNode; if (join.getType().equals(JoinNode.Type.LEFT)) { innerNode = join.getRight(); } else { innerNode = join.getLeft(); } return innerNode; }
private static int checkAlignment(JoinNode joinNode, Set<Symbol> maybeLeftSymbols, Set<Symbol> maybeRightSymbols) { List<Symbol> leftSymbols = joinNode.getLeft().getOutputSymbols(); List<Symbol> rightSymbols = joinNode.getRight().getOutputSymbols(); if (leftSymbols.containsAll(maybeLeftSymbols) && containsNone(leftSymbols, maybeRightSymbols) && rightSymbols.containsAll(maybeRightSymbols) && containsNone(rightSymbols, maybeLeftSymbols)) { return 1; } if (leftSymbols.containsAll(maybeRightSymbols) && containsNone(leftSymbols, maybeLeftSymbols) && rightSymbols.containsAll(maybeLeftSymbols) && containsNone(rightSymbols, maybeRightSymbols)) { return -1; } return 0; }
private PlanNode pushPartialToRightChild(AggregationNode node, JoinNode child, Context context) { Set<Symbol> joinRightChildSymbols = ImmutableSet.copyOf(child.getRight().getOutputSymbols()); List<Symbol> groupingSet = getPushedDownGroupingSet(node, joinRightChildSymbols, intersection(getJoinRequiredSymbols(child), joinRightChildSymbols)); AggregationNode pushedAggregation = replaceAggregationSource(node, child.getRight(), groupingSet); return pushPartialToJoin(node, child, child.getLeft(), pushedAggregation, context); }
@Override public JoinGraph visitJoin(JoinNode node, Context context) { //TODO: add support for non inner joins if (node.getType() != INNER) { return visitPlan(node, context); } JoinGraph left = node.getLeft().accept(this, context); JoinGraph right = node.getRight().accept(this, context); JoinGraph graph = left.joinWith(right, node.getCriteria(), context, node.getId()); if (node.getFilter().isPresent()) { return graph.withFilter(node.getFilter().get()); } return graph; }
private JoinEnumerationResult setJoinNodeProperties(JoinNode joinNode) { // TODO avoid stat (but not cost) recalculation for all considered (distribution,flip) pairs, since resulting relation is the same in all case if (isAtMostScalar(joinNode.getRight(), lookup)) { return createJoinEnumerationResult(joinNode.withDistributionType(REPLICATED)); } if (isAtMostScalar(joinNode.getLeft(), lookup)) { return createJoinEnumerationResult(joinNode.flipChildren().withDistributionType(REPLICATED)); } List<JoinEnumerationResult> possibleJoinNodes = getPossibleJoinNodes(joinNode, getJoinDistributionType(session)); verify(!possibleJoinNodes.isEmpty(), "possibleJoinNodes is empty"); if (possibleJoinNodes.stream().anyMatch(UNKNOWN_COST_RESULT::equals)) { return UNKNOWN_COST_RESULT; } return resultComparator.min(possibleJoinNodes); }
private PlanNodeStatsEstimate crossJoinStats(JoinNode node, PlanNodeStatsEstimate leftStats, PlanNodeStatsEstimate rightStats, TypeProvider types) { PlanNodeStatsEstimate.Builder builder = PlanNodeStatsEstimate.builder() .setOutputRowCount(leftStats.getOutputRowCount() * rightStats.getOutputRowCount()); node.getLeft().getOutputSymbols().forEach(symbol -> builder.addSymbolStatistics(symbol, leftStats.getSymbolStatistics(symbol))); node.getRight().getOutputSymbols().forEach(symbol -> builder.addSymbolStatistics(symbol, rightStats.getSymbolStatistics(symbol))); return normalizer.normalize(builder.build(), types); }
@Override public Result apply(AggregationNode aggregationNode, Captures captures, Context context) { JoinNode joinNode = captures.get(JOIN_NODE); if (joinNode.getType() != JoinNode.Type.INNER) { return Result.empty(); } // TODO: leave partial aggregation above Join? if (allAggregationsOn(aggregationNode.getAggregations(), joinNode.getLeft().getOutputSymbols())) { return Result.ofPlanNode(pushPartialToLeftChild(aggregationNode, joinNode, context)); } else if (allAggregationsOn(aggregationNode.getAggregations(), joinNode.getRight().getOutputSymbols())) { return Result.ofPlanNode(pushPartialToRightChild(aggregationNode, joinNode, context)); } return Result.empty(); }