@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())); } }
public JoinNode flipChildren() { return new JoinNode( getId(), flipType(type), right, left, flipJoinCriteria(criteria), flipOutputSymbols(getOutputSymbols(), left, right), filter, rightHashSymbol, leftHashSymbol, distributionType); }
@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 PlanWithProperties buildJoin(JoinNode node, PlanWithProperties newLeft, PlanWithProperties newRight, JoinNode.DistributionType newDistributionType) { JoinNode result = new JoinNode(node.getId(), node.getType(), newLeft.getNode(), newRight.getNode(), node.getCriteria(), node.getOutputSymbols(), node.getFilter(), node.getLeftHashSymbol(), node.getRightHashSymbol(), Optional.of(newDistributionType)); return new PlanWithProperties(result, deriveProperties(result, ImmutableList.of(newLeft.getProperties(), newRight.getProperties()))); }
@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()); } }
.filter(symbol -> node.getOutputSymbols().contains(symbol) || hashSymbolsWithParentPreferences.values().contains(symbol)) .collect(toImmutableList()); new JoinNode( node.getId(), node.getType(), left.getNode(), right.getNode(), node.getCriteria(), outputSymbols, node.getFilter(), leftHashSymbol, rightHashSymbol, node.getDistributionType()), hashSymbolsWithParentPreferences);
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 void flattenNode(PlanNode node, int limit) { PlanNode resolved = lookup.resolve(node); // (limit - 2) because you need to account for adding left and right side if (!(resolved instanceof JoinNode) || (sources.size() > (limit - 2))) { sources.add(node); return; } JoinNode joinNode = (JoinNode) resolved; if (joinNode.getType() != INNER || !isDeterministic(joinNode.getFilter().orElse(TRUE_LITERAL)) || joinNode.getDistributionType().isPresent()) { sources.add(node); return; } // we set the left limit to limit - 1 to account for the node on the right flattenNode(joinNode.getLeft(), limit - 1); flattenNode(joinNode.getRight(), limit); joinNode.getCriteria().stream() .map(EquiJoinClause::toExpression) .forEach(filters::add); joinNode.getFilter().ifPresent(filters::add); }
@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; }
@Override public PlanNode visitJoin(JoinNode node, List<PlanNode> newChildren) { checkArgument(newChildren.size() == 2, "expected newChildren to contain 2 nodes"); return new JoinNode(node.getId(), node.getType(), newChildren.get(0), newChildren.get(1), node.getCriteria(), node.getLeftHashSymbol(), node.getRightHashSymbol()); }
private Set<Symbol> getJoinRequiredSymbols(JoinNode node) { return Streams.concat( node.getCriteria().stream().map(JoinNode.EquiJoinClause::getLeft), node.getCriteria().stream().map(JoinNode.EquiJoinClause::getRight), node.getFilter().map(SymbolsExtractor::extractUnique).orElse(ImmutableSet.of()).stream(), node.getLeftHashSymbol().map(ImmutableSet::of).orElse(ImmutableSet.of()).stream(), node.getRightHashSymbol().map(ImmutableSet::of).orElse(ImmutableSet.of()).stream()) .collect(toImmutableSet()); }
private static JoinNode leftOuterJoin(PlanNodeIdAllocator idAllocator, AssignUniqueId probeSide, ProjectNode buildSide, Expression joinExpression) { return new JoinNode( idAllocator.getNextId(), JoinNode.Type.LEFT, probeSide, buildSide, ImmutableList.of(), ImmutableList.<Symbol>builder() .addAll(probeSide.getOutputSymbols()) .addAll(buildSide.getOutputSymbols()) .build(), Optional.of(joinExpression), Optional.empty(), Optional.empty(), Optional.empty()); }
@Override public GroupedExecutionProperties visitJoin(JoinNode node, Void context) GroupedExecutionProperties left = node.getLeft().accept(this, null); GroupedExecutionProperties right = node.getRight().accept(this, null); if (!node.getDistributionType().isPresent()) { if ((node.getType() == JoinNode.Type.RIGHT || node.getType() == JoinNode.Type.FULL) && !right.currentNodeCapable) { switch (node.getDistributionType().get()) { case REPLICATED: throw new UnsupportedOperationException("Unknown distribution type: " + node.getDistributionType());
@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()); }
boolean unordered = spillPossible(session, node.getType()); switch (node.getType()) { case INNER: probeProperties = probeProperties.translate(column -> filterOrRewrite(node.getOutputSymbols(), node.getCriteria(), column)); buildProperties = buildProperties.translate(column -> filterOrRewrite(node.getOutputSymbols(), node.getCriteria(), column)); if (node.isCrossJoin()) { .build(); case LEFT: return ActualProperties.builderFrom(probeProperties.translate(column -> filterIfMissing(node.getOutputSymbols(), column))) .unordered(unordered) .build(); case RIGHT: buildProperties = buildProperties.translate(column -> filterIfMissing(node.getOutputSymbols(), column)); return ActualProperties.builderFrom(buildProperties.translate(column -> filterIfMissing(node.getOutputSymbols(), column))) .local(ImmutableList.of()) .unordered(unordered) ImmutableList.Builder<Expression> coalesceExpressions = ImmutableList.builder(); for (Symbol column : nodePartitioning.getColumns()) { for (JoinNode.EquiJoinClause equality : node.getCriteria()) { if (equality.getLeft().equals(column) || equality.getRight().equals(column)) { coalesceExpressions.add(new CoalesceExpression(ImmutableList.of(equality.getLeft().toSymbolReference(), equality.getRight().toSymbolReference()))); .build(); default:
private OperatorFactory createLookupJoin( JoinNode node, PhysicalOperation probeSource, List<Symbol> probeSymbols, Optional<Symbol> probeHashSymbol, JoinBridgeManager<? extends LookupSourceFactory> lookupSourceFactoryManager, LocalExecutionPlanContext context) { List<Type> probeTypes = probeSource.getTypes(); List<Symbol> probeOutputSymbols = node.getOutputSymbols().stream() .filter(symbol -> node.getLeft().getOutputSymbols().contains(symbol)) .collect(toImmutableList()); List<Integer> probeOutputChannels = ImmutableList.copyOf(getChannelsForSymbols(probeOutputSymbols, probeSource.getLayout())); List<Integer> probeJoinChannels = ImmutableList.copyOf(getChannelsForSymbols(probeSymbols, probeSource.getLayout())); OptionalInt probeHashChannel = probeHashSymbol.map(channelGetter(probeSource)) .map(OptionalInt::of).orElse(OptionalInt.empty()); OptionalInt totalOperatorsCount = getJoinOperatorsCountForSpill(context, session); switch (node.getType()) { case INNER: return lookupJoinOperators.innerJoin(context.getNextOperatorId(), node.getId(), lookupSourceFactoryManager, probeTypes, probeJoinChannels, probeHashChannel, Optional.of(probeOutputChannels), totalOperatorsCount, partitioningSpillerFactory); case LEFT: return lookupJoinOperators.probeOuterJoin(context.getNextOperatorId(), node.getId(), lookupSourceFactoryManager, probeTypes, probeJoinChannels, probeHashChannel, Optional.of(probeOutputChannels), totalOperatorsCount, partitioningSpillerFactory); case RIGHT: return lookupJoinOperators.lookupOuterJoin(context.getNextOperatorId(), node.getId(), lookupSourceFactoryManager, probeTypes, probeJoinChannels, probeHashChannel, Optional.of(probeOutputChannels), totalOperatorsCount, partitioningSpillerFactory); case FULL: return lookupJoinOperators.fullOuterJoin(context.getNextOperatorId(), node.getId(), lookupSourceFactoryManager, probeTypes, probeJoinChannels, probeHashChannel, Optional.of(probeOutputChannels), totalOperatorsCount, partitioningSpillerFactory); default: throw new UnsupportedOperationException("Unsupported join type: " + node.getType()); } }
private static boolean mustReplicate(JoinNode joinNode, Context context) { JoinNode.Type type = joinNode.getType(); if (joinNode.getCriteria().isEmpty() && (type == INNER || type == LEFT)) { // There is nothing to partition on return true; } return isAtMostScalar(joinNode.getRight(), context.getLookup()); }
private PhysicalOperation createNestedLoopJoin(JoinNode node, LocalExecutionPlanContext context) PhysicalOperation probeSource = node.getLeft().accept(this, context); PhysicalOperation buildSource = node.getRight().accept(this, buildContext); checkArgument(node.getType() == INNER, "NestedLoopJoin is only used for inner join"); NestedLoopBuildOperatorFactory nestedLoopBuildOperatorFactory = new NestedLoopBuildOperatorFactory( buildContext.getNextOperatorId(), node.getId(), nestedLoopJoinBridgeManager); OperatorFactory operatorFactory = new NestedLoopJoinOperatorFactory(context.getNextOperatorId(), node.getId(), nestedLoopJoinBridgeManager); return new PhysicalOperation(operatorFactory, outputMappings.build(), context, probeSource);