Search in sources :

Example 1 with SemiJoinNode

use of io.trino.sql.planner.plan.SemiJoinNode in project trino by trinodb.

the class TransformFilteringSemiJoinToInnerJoin method apply.

@Override
public Result apply(FilterNode filterNode, Captures captures, Context context) {
    SemiJoinNode semiJoin = captures.get(SEMI_JOIN);
    // Do not transform semi-join in context of DELETE
    if (PlanNodeSearcher.searchFrom(semiJoin.getSource(), context.getLookup()).where(node -> node instanceof TableScanNode && ((TableScanNode) node).isUpdateTarget()).matches()) {
        return Result.empty();
    }
    Symbol semiJoinSymbol = semiJoin.getSemiJoinOutput();
    Predicate<Expression> isSemiJoinSymbol = expression -> expression.equals(semiJoinSymbol.toSymbolReference());
    List<Expression> conjuncts = extractConjuncts(filterNode.getPredicate());
    if (conjuncts.stream().noneMatch(isSemiJoinSymbol)) {
        return Result.empty();
    }
    Expression filteredPredicate = and(conjuncts.stream().filter(not(isSemiJoinSymbol)).collect(toImmutableList()));
    Expression simplifiedPredicate = inlineSymbols(symbol -> {
        if (symbol.equals(semiJoinSymbol)) {
            return TRUE_LITERAL;
        }
        return symbol.toSymbolReference();
    }, filteredPredicate);
    Optional<Expression> joinFilter = simplifiedPredicate.equals(TRUE_LITERAL) ? Optional.empty() : Optional.of(simplifiedPredicate);
    PlanNode filteringSourceDistinct = new AggregationNode(context.getIdAllocator().getNextId(), semiJoin.getFilteringSource(), ImmutableMap.of(), singleGroupingSet(ImmutableList.of(semiJoin.getFilteringSourceJoinSymbol())), ImmutableList.of(), SINGLE, Optional.empty(), Optional.empty());
    JoinNode innerJoin = new JoinNode(semiJoin.getId(), INNER, semiJoin.getSource(), filteringSourceDistinct, ImmutableList.of(new EquiJoinClause(semiJoin.getSourceJoinSymbol(), semiJoin.getFilteringSourceJoinSymbol())), semiJoin.getSource().getOutputSymbols(), ImmutableList.of(), false, joinFilter, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), semiJoin.getDynamicFilterId().map(id -> ImmutableMap.of(id, semiJoin.getFilteringSourceJoinSymbol())).orElse(ImmutableMap.of()), Optional.empty());
    ProjectNode project = new ProjectNode(context.getIdAllocator().getNextId(), innerJoin, Assignments.builder().putIdentities(innerJoin.getOutputSymbols()).put(semiJoinSymbol, TRUE_LITERAL).build());
    return Result.ofPlanNode(project);
}
Also used : INNER(io.trino.sql.planner.plan.JoinNode.Type.INNER) Patterns.filter(io.trino.sql.planner.plan.Patterns.filter) SINGLE(io.trino.sql.planner.plan.AggregationNode.Step.SINGLE) SystemSessionProperties.isRewriteFilteringSemiJoinToInnerJoin(io.trino.SystemSessionProperties.isRewriteFilteringSemiJoinToInnerJoin) Capture.newCapture(io.trino.matching.Capture.newCapture) FilterNode(io.trino.sql.planner.plan.FilterNode) PlanNode(io.trino.sql.planner.plan.PlanNode) ExpressionSymbolInliner.inlineSymbols(io.trino.sql.planner.ExpressionSymbolInliner.inlineSymbols) ImmutableList(com.google.common.collect.ImmutableList) PlanNodeSearcher(io.trino.sql.planner.optimizations.PlanNodeSearcher) EquiJoinClause(io.trino.sql.planner.plan.JoinNode.EquiJoinClause) AggregationNode(io.trino.sql.planner.plan.AggregationNode) Rule(io.trino.sql.planner.iterative.Rule) JoinNode(io.trino.sql.planner.plan.JoinNode) ProjectNode(io.trino.sql.planner.plan.ProjectNode) TableScanNode(io.trino.sql.planner.plan.TableScanNode) Symbol(io.trino.sql.planner.Symbol) ImmutableMap(com.google.common.collect.ImmutableMap) Predicate(java.util.function.Predicate) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) Assignments(io.trino.sql.planner.plan.Assignments) Patterns.semiJoin(io.trino.sql.planner.plan.Patterns.semiJoin) SemiJoinNode(io.trino.sql.planner.plan.SemiJoinNode) TRUE_LITERAL(io.trino.sql.tree.BooleanLiteral.TRUE_LITERAL) Capture(io.trino.matching.Capture) AggregationNode.singleGroupingSet(io.trino.sql.planner.plan.AggregationNode.singleGroupingSet) List(java.util.List) Pattern(io.trino.matching.Pattern) ExpressionUtils.and(io.trino.sql.ExpressionUtils.and) Patterns.source(io.trino.sql.planner.plan.Patterns.source) Captures(io.trino.matching.Captures) Optional(java.util.Optional) Expression(io.trino.sql.tree.Expression) ExpressionUtils.extractConjuncts(io.trino.sql.ExpressionUtils.extractConjuncts) Predicate.not(java.util.function.Predicate.not) Session(io.trino.Session) Symbol(io.trino.sql.planner.Symbol) JoinNode(io.trino.sql.planner.plan.JoinNode) SemiJoinNode(io.trino.sql.planner.plan.SemiJoinNode) EquiJoinClause(io.trino.sql.planner.plan.JoinNode.EquiJoinClause) AggregationNode(io.trino.sql.planner.plan.AggregationNode) SemiJoinNode(io.trino.sql.planner.plan.SemiJoinNode) PlanNode(io.trino.sql.planner.plan.PlanNode) TableScanNode(io.trino.sql.planner.plan.TableScanNode) Expression(io.trino.sql.tree.Expression) ProjectNode(io.trino.sql.planner.plan.ProjectNode)

Example 2 with SemiJoinNode

use of io.trino.sql.planner.plan.SemiJoinNode in project trino by trinodb.

the class TestEffectivePredicateExtractor method testSemiJoin.

@Test
public void testSemiJoin() {
    PlanNode node = new SemiJoinNode(newId(), filter(baseTableScan, and(greaterThan(AE, bigintLiteral(10)), lessThan(AE, bigintLiteral(100)))), filter(baseTableScan, greaterThan(AE, bigintLiteral(5))), A, B, C, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty());
    Expression effectivePredicate = effectivePredicateExtractor.extract(SESSION, node, TypeProvider.empty(), typeAnalyzer);
    // Currently, only pull predicates through the source plan
    assertEquals(normalizeConjuncts(effectivePredicate), normalizeConjuncts(and(greaterThan(AE, bigintLiteral(10)), lessThan(AE, bigintLiteral(100)))));
}
Also used : PlanNode(io.trino.sql.planner.plan.PlanNode) InListExpression(io.trino.sql.tree.InListExpression) NotExpression(io.trino.sql.tree.NotExpression) ComparisonExpression(io.trino.sql.tree.ComparisonExpression) Expression(io.trino.sql.tree.Expression) SemiJoinNode(io.trino.sql.planner.plan.SemiJoinNode) Test(org.testng.annotations.Test)

Example 3 with SemiJoinNode

use of io.trino.sql.planner.plan.SemiJoinNode in project trino by trinodb.

the class SimpleFilterProjectSemiJoinStatsRule method calculate.

private Optional<PlanNodeStatsEstimate> calculate(FilterNode filterNode, SemiJoinNode semiJoinNode, StatsProvider statsProvider, Session session, TypeProvider types) {
    PlanNodeStatsEstimate sourceStats = statsProvider.getStats(semiJoinNode.getSource());
    PlanNodeStatsEstimate filteringSourceStats = statsProvider.getStats(semiJoinNode.getFilteringSource());
    Symbol filteringSourceJoinSymbol = semiJoinNode.getFilteringSourceJoinSymbol();
    Symbol sourceJoinSymbol = semiJoinNode.getSourceJoinSymbol();
    Optional<SemiJoinOutputFilter> semiJoinOutputFilter = extractSemiJoinOutputFilter(filterNode.getPredicate(), semiJoinNode.getSemiJoinOutput());
    if (semiJoinOutputFilter.isEmpty()) {
        return Optional.empty();
    }
    PlanNodeStatsEstimate semiJoinStats;
    if (semiJoinOutputFilter.get().isNegated()) {
        semiJoinStats = computeAntiJoin(sourceStats, filteringSourceStats, sourceJoinSymbol, filteringSourceJoinSymbol);
    } else {
        semiJoinStats = computeSemiJoin(sourceStats, filteringSourceStats, sourceJoinSymbol, filteringSourceJoinSymbol);
    }
    if (semiJoinStats.isOutputRowCountUnknown()) {
        return Optional.of(PlanNodeStatsEstimate.unknown());
    }
    // apply remaining predicate
    PlanNodeStatsEstimate filteredStats = filterStatsCalculator.filterStats(semiJoinStats, semiJoinOutputFilter.get().getRemainingPredicate(), session, types);
    if (filteredStats.isOutputRowCountUnknown()) {
        return Optional.of(semiJoinStats.mapOutputRowCount(rowCount -> rowCount * UNKNOWN_FILTER_COEFFICIENT));
    }
    return Optional.of(filteredStats);
}
Also used : Symbol(io.trino.sql.planner.Symbol) Iterables(com.google.common.collect.Iterables) Lookup(io.trino.sql.planner.iterative.Lookup) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) Patterns.filter(io.trino.sql.planner.plan.Patterns.filter) SemiJoinNode(io.trino.sql.planner.plan.SemiJoinNode) UNKNOWN_FILTER_COEFFICIENT(io.trino.cost.FilterStatsCalculator.UNKNOWN_FILTER_COEFFICIENT) FilterNode(io.trino.sql.planner.plan.FilterNode) PlanNode(io.trino.sql.planner.plan.PlanNode) SemiJoinStatsCalculator.computeSemiJoin(io.trino.cost.SemiJoinStatsCalculator.computeSemiJoin) List(java.util.List) Pattern(io.trino.matching.Pattern) SymbolReference(io.trino.sql.tree.SymbolReference) SemiJoinStatsCalculator.computeAntiJoin(io.trino.cost.SemiJoinStatsCalculator.computeAntiJoin) NotExpression(io.trino.sql.tree.NotExpression) Objects.requireNonNull(java.util.Objects.requireNonNull) Metadata(io.trino.metadata.Metadata) TypeProvider(io.trino.sql.planner.TypeProvider) Optional(java.util.Optional) Expression(io.trino.sql.tree.Expression) ExpressionUtils.extractConjuncts(io.trino.sql.ExpressionUtils.extractConjuncts) ExpressionUtils.combineConjuncts(io.trino.sql.ExpressionUtils.combineConjuncts) ProjectNode(io.trino.sql.planner.plan.ProjectNode) Session(io.trino.Session) Symbol(io.trino.sql.planner.Symbol)

Example 4 with SemiJoinNode

use of io.trino.sql.planner.plan.SemiJoinNode in project trino by trinodb.

the class SemiJoinMatcher method detailMatches.

@Override
public MatchResult detailMatches(PlanNode node, StatsProvider stats, Session session, Metadata metadata, SymbolAliases symbolAliases) {
    checkState(shapeMatches(node), "Plan testing framework error: shapeMatches returned false in detailMatches in %s", this.getClass().getName());
    SemiJoinNode semiJoinNode = (SemiJoinNode) node;
    if (!(symbolAliases.get(sourceSymbolAlias).equals(semiJoinNode.getSourceJoinSymbol().toSymbolReference()) && symbolAliases.get(filteringSymbolAlias).equals(semiJoinNode.getFilteringSourceJoinSymbol().toSymbolReference()))) {
        return NO_MATCH;
    }
    if (distributionType.isPresent() && !distributionType.equals(semiJoinNode.getDistributionType())) {
        return NO_MATCH;
    }
    if (hasDynamicFilter.isPresent()) {
        if (hasDynamicFilter.get()) {
            if (semiJoinNode.getDynamicFilterId().isEmpty()) {
                return NO_MATCH;
            }
            DynamicFilterId dynamicFilterId = semiJoinNode.getDynamicFilterId().get();
            List<DynamicFilters.Descriptor> matchingDescriptors = searchFrom(semiJoinNode.getSource()).where(FilterNode.class::isInstance).findAll().stream().flatMap(filterNode -> extractExpressions(filterNode).stream()).flatMap(expression -> extractDynamicFilters(expression).getDynamicConjuncts().stream()).filter(descriptor -> descriptor.getId().equals(dynamicFilterId)).collect(toImmutableList());
            boolean sourceSymbolsMatch = matchingDescriptors.stream().map(descriptor -> Symbol.from(descriptor.getInput())).allMatch(sourceSymbol -> symbolAliases.get(sourceSymbolAlias).equals(sourceSymbol.toSymbolReference()));
            if (!matchingDescriptors.isEmpty() && sourceSymbolsMatch) {
                return match(outputAlias, semiJoinNode.getSemiJoinOutput().toSymbolReference());
            }
            return NO_MATCH;
        }
        if (semiJoinNode.getDynamicFilterId().isPresent()) {
            return NO_MATCH;
        }
    }
    return match(outputAlias, semiJoinNode.getSemiJoinOutput().toSymbolReference());
}
Also used : Symbol(io.trino.sql.planner.Symbol) MatchResult.match(io.trino.sql.planner.assertions.MatchResult.match) PlanNodeSearcher.searchFrom(io.trino.sql.planner.optimizations.PlanNodeSearcher.searchFrom) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) DynamicFilters.extractDynamicFilters(io.trino.sql.DynamicFilters.extractDynamicFilters) SemiJoinNode(io.trino.sql.planner.plan.SemiJoinNode) StatsProvider(io.trino.cost.StatsProvider) FilterNode(io.trino.sql.planner.plan.FilterNode) DynamicFilterId(io.trino.sql.planner.plan.DynamicFilterId) PlanNode(io.trino.sql.planner.plan.PlanNode) Preconditions.checkState(com.google.common.base.Preconditions.checkState) List(java.util.List) DynamicFilters(io.trino.sql.DynamicFilters) Objects.requireNonNull(java.util.Objects.requireNonNull) ExpressionExtractor.extractExpressions(io.trino.sql.planner.ExpressionExtractor.extractExpressions) Metadata(io.trino.metadata.Metadata) Optional(java.util.Optional) NO_MATCH(io.trino.sql.planner.assertions.MatchResult.NO_MATCH) Session(io.trino.Session) MoreObjects.toStringHelper(com.google.common.base.MoreObjects.toStringHelper) FilterNode(io.trino.sql.planner.plan.FilterNode) SemiJoinNode(io.trino.sql.planner.plan.SemiJoinNode) DynamicFilterId(io.trino.sql.planner.plan.DynamicFilterId)

Example 5 with SemiJoinNode

use of io.trino.sql.planner.plan.SemiJoinNode in project trino by trinodb.

the class SimpleFilterProjectSemiJoinStatsRule method doCalculate.

@Override
protected Optional<PlanNodeStatsEstimate> doCalculate(FilterNode node, StatsProvider sourceStats, Lookup lookup, Session session, TypeProvider types) {
    PlanNode nodeSource = lookup.resolve(node.getSource());
    SemiJoinNode semiJoinNode;
    if (nodeSource instanceof ProjectNode) {
        ProjectNode projectNode = (ProjectNode) nodeSource;
        if (!projectNode.isIdentity()) {
            return Optional.empty();
        }
        PlanNode projectNodeSource = lookup.resolve(projectNode.getSource());
        if (!(projectNodeSource instanceof SemiJoinNode)) {
            return Optional.empty();
        }
        semiJoinNode = (SemiJoinNode) projectNodeSource;
    } else if (nodeSource instanceof SemiJoinNode) {
        semiJoinNode = (SemiJoinNode) nodeSource;
    } else {
        return Optional.empty();
    }
    return calculate(node, semiJoinNode, sourceStats, session, types);
}
Also used : PlanNode(io.trino.sql.planner.plan.PlanNode) ProjectNode(io.trino.sql.planner.plan.ProjectNode) SemiJoinNode(io.trino.sql.planner.plan.SemiJoinNode)

Aggregations

SemiJoinNode (io.trino.sql.planner.plan.SemiJoinNode)7 PlanNode (io.trino.sql.planner.plan.PlanNode)6 Expression (io.trino.sql.tree.Expression)5 Symbol (io.trino.sql.planner.Symbol)4 ProjectNode (io.trino.sql.planner.plan.ProjectNode)4 ImmutableList.toImmutableList (com.google.common.collect.ImmutableList.toImmutableList)3 Session (io.trino.Session)3 Pattern (io.trino.matching.Pattern)3 FilterNode (io.trino.sql.planner.plan.FilterNode)3 List (java.util.List)3 Objects.requireNonNull (java.util.Objects.requireNonNull)3 Optional (java.util.Optional)3 ImmutableList (com.google.common.collect.ImmutableList)2 Capture (io.trino.matching.Capture)2 Capture.newCapture (io.trino.matching.Capture.newCapture)2 Captures (io.trino.matching.Captures)2 Metadata (io.trino.metadata.Metadata)2 ExpressionUtils.extractConjuncts (io.trino.sql.ExpressionUtils.extractConjuncts)2 Rule (io.trino.sql.planner.iterative.Rule)2 Patterns.filter (io.trino.sql.planner.plan.Patterns.filter)2