use of io.prestosql.sql.planner.iterative.Lookup in project hetu-core by openlookeng.
the class RuleAssert method applyRule.
private RuleApplication applyRule() {
PlanSymbolAllocator planSymbolAllocator = new PlanSymbolAllocator(types.allTypes());
Memo memo = new Memo(idAllocator, plan);
Lookup lookup = Lookup.from(planNode -> Stream.of(memo.resolve(planNode)));
PlanNode memoRoot = memo.getNode(memo.getRootGroup());
return inTransaction(session -> applyRule(rule, memoRoot, ruleContext(statsCalculator, costCalculator, planSymbolAllocator, memo, lookup, session)));
}
use of io.prestosql.sql.planner.iterative.Lookup in project hetu-core by openlookeng.
the class TableScanStatsRule method doCalculate.
@Override
protected Optional<PlanNodeStatsEstimate> doCalculate(TableScanNode node, StatsProvider sourceStats, Lookup lookup, Session session, TypeProvider types) {
// TODO Construct predicate like AddExchanges's LayoutConstraintEvaluator
TupleDomain<ColumnHandle> predicate = metadata.getTableProperties(session, node.getTable()).getPredicate();
Constraint constraint = new Constraint(predicate);
TableStatistics tableStatistics = metadata.getTableStatistics(session, node.getTable(), constraint, true);
verify(tableStatistics != null, "tableStatistics is null for %s", node);
Map<Symbol, SymbolStatsEstimate> outputSymbolStats = new HashMap<>();
Map<ColumnHandle, Symbol> remainingSymbols = new HashMap<>();
Map<ColumnHandle, Symbol> assignments = ImmutableBiMap.copyOf(node.getAssignments()).inverse();
boolean isPredicatesPushDown = false;
if ((predicate.isAll() || predicate.getDomains().get().equals(node.getEnforcedConstraint().getDomains().get())) && !(node.getEnforcedConstraint().isAll() || node.getEnforcedConstraint().isNone())) {
predicate = node.getEnforcedConstraint();
isPredicatesPushDown = true;
predicate.getDomains().get().entrySet().stream().forEach(e -> {
remainingSymbols.put(e.getKey(), new Symbol(e.getKey().getColumnName()));
});
}
for (Map.Entry<Symbol, ColumnHandle> entry : node.getAssignments().entrySet()) {
Symbol symbol = entry.getKey();
Optional<ColumnStatistics> columnStatistics = Optional.ofNullable(tableStatistics.getColumnStatistics().get(entry.getValue()));
SymbolStatsEstimate symbolStatistics = columnStatistics.map(statistics -> toSymbolStatistics(tableStatistics, statistics, types.get(symbol))).orElse(SymbolStatsEstimate.unknown());
outputSymbolStats.put(symbol, symbolStatistics);
remainingSymbols.remove(entry.getValue());
}
PlanNodeStatsEstimate tableEstimates = PlanNodeStatsEstimate.builder().setOutputRowCount(tableStatistics.getRowCount().getValue()).addSymbolStatistics(outputSymbolStats).build();
if (isPredicatesPushDown) {
if (remainingSymbols.size() > 0) {
ImmutableBiMap.Builder<ColumnHandle, Symbol> assignmentBuilder = ImmutableBiMap.builder();
assignments = assignmentBuilder.putAll(assignments).putAll(remainingSymbols).build();
for (Map.Entry<ColumnHandle, Symbol> entry : remainingSymbols.entrySet()) {
Symbol symbol = entry.getValue();
Optional<ColumnStatistics> columnStatistics = Optional.ofNullable(tableStatistics.getColumnStatistics().get(entry.getKey()));
SymbolStatsEstimate symbolStatistics = columnStatistics.map(statistics -> toSymbolStatistics(tableStatistics, statistics, types.get(symbol))).orElse(SymbolStatsEstimate.unknown());
outputSymbolStats.put(symbol, symbolStatistics);
}
/* Refresh TableEstimates for remaining columns */
tableEstimates = PlanNodeStatsEstimate.builder().setOutputRowCount(tableStatistics.getRowCount().getValue()).addSymbolStatistics(outputSymbolStats).build();
}
Expression pushDownExpression = domainTranslator.toPredicate(predicate.transform(assignments::get));
PlanNodeStatsEstimate estimate = filterStatsCalculator.filterStats(tableEstimates, pushDownExpression, session, types);
if ((isDefaultFilterFactorEnabled(session) || sourceStats.isEnforceDefaultFilterFactor()) && estimate.isOutputRowCountUnknown()) {
PlanNodeStatsEstimate finalTableEstimates = tableEstimates;
estimate = tableEstimates.mapOutputRowCount(sourceRowCount -> finalTableEstimates.getOutputRowCount() * UNKNOWN_FILTER_COEFFICIENT);
}
return Optional.of(estimate);
}
return Optional.of(tableEstimates);
}
use of io.prestosql.sql.planner.iterative.Lookup in project hetu-core by openlookeng.
the class TopNStatsRule method doCalculate.
@Override
protected Optional<PlanNodeStatsEstimate> doCalculate(TopNNode node, StatsProvider statsProvider, Lookup lookup, Session session, TypeProvider types) {
PlanNodeStatsEstimate sourceStats = statsProvider.getStats(node.getSource());
double rowCount = sourceStats.getOutputRowCount();
if (rowCount <= node.getCount()) {
return Optional.of(sourceStats);
}
long limitCount = node.getCount();
PlanNodeStatsEstimate resultStats = PlanNodeStatsEstimate.buildFrom(sourceStats).setOutputRowCount(limitCount).build();
if (limitCount == 0) {
return Optional.of(resultStats);
}
// augment null fraction estimation for first ORDER BY symbol
// Assuming not empty list
Symbol firstOrderSymbol = node.getOrderingScheme().getOrderBy().get(0);
SortOrder sortOrder = node.getOrderingScheme().getOrdering(firstOrderSymbol);
resultStats = resultStats.mapSymbolColumnStatistics(firstOrderSymbol, symbolStats -> {
SymbolStatsEstimate.Builder newStats = SymbolStatsEstimate.buildFrom(symbolStats);
double nullCount = rowCount * symbolStats.getNullsFraction();
if (sortOrder.isNullsFirst()) {
if (nullCount > limitCount) {
newStats.setNullsFraction(1.0);
} else {
newStats.setNullsFraction(nullCount / limitCount);
}
} else {
double nonNullCount = (rowCount - nullCount);
if (nonNullCount > limitCount) {
newStats.setNullsFraction(0.0);
} else {
newStats.setNullsFraction((limitCount - nonNullCount) / limitCount);
}
}
return newStats.build();
});
// TopN actually limits (or when there was no row count estimated for source)
return Optional.of(resultStats);
}
use of io.prestosql.sql.planner.iterative.Lookup in project hetu-core by openlookeng.
the class FilterStatsRule method doCalculate.
@Override
public Optional<PlanNodeStatsEstimate> doCalculate(FilterNode node, StatsProvider statsProvider, Lookup lookup, Session session, TypeProvider types) {
PlanNodeStatsEstimate sourceStats = statsProvider.getStats(node.getSource());
PlanNodeStatsEstimate estimate;
if (isExpression(node.getPredicate())) {
estimate = filterStatsCalculator.filterStats(sourceStats, castToExpression(node.getPredicate()), session, types);
} else {
Map<Integer, Symbol> layout = new HashMap<>();
int channel = 0;
for (Symbol symbol : node.getSource().getOutputSymbols()) {
layout.put(channel++, symbol);
}
estimate = filterStatsCalculator.filterStats(sourceStats, node.getPredicate(), session, types, layout);
}
if ((isDefaultFilterFactorEnabled(session) || statsProvider.isEnforceDefaultFilterFactor()) && estimate.isOutputRowCountUnknown()) {
estimate = sourceStats.mapOutputRowCount(sourceRowCount -> sourceStats.getOutputRowCount() * UNKNOWN_FILTER_COEFFICIENT);
}
return Optional.of(estimate);
}
use of io.prestosql.sql.planner.iterative.Lookup in project hetu-core by openlookeng.
the class TablePushdown method apply.
@Override
public Result apply(JoinNode node, Captures captures, Context context) {
uniqueColumnsPerTable = getUniqueColumnTableMap();
ruleContext = context;
Lookup lookup = ruleContext.getLookup();
if (verifyJoinConditions(node, lookup)) {
LOG.info("Table Pushdown preconditions satisfied.");
PlanNode rewrittenNode = planRewriter(node, lookup);
clearAllDataStructures();
return Result.ofPlanNode(rewrittenNode);
}
return Result.empty();
}
Aggregations