use of io.prestosql.spi.plan.JoinNode in project hetu-core by openlookeng.
the class PushTopNThroughOuterJoin method apply.
@Override
public Result apply(TopNNode parent, Captures captures, Context context) {
JoinNode joinNode = captures.get(JOIN_CHILD);
List<Symbol> orderBySymbols = parent.getOrderingScheme().getOrderBy();
PlanNode left = joinNode.getLeft();
PlanNode right = joinNode.getRight();
JoinNode.Type type = joinNode.getType();
if ((type == LEFT) && ImmutableSet.copyOf(left.getOutputSymbols()).containsAll(orderBySymbols) && !isAtMost(left, context.getLookup(), parent.getCount())) {
return Result.ofPlanNode(joinNode.replaceChildren(ImmutableList.of(parent.replaceChildren(ImmutableList.of(left)), right)));
}
if ((type == RIGHT) && ImmutableSet.copyOf(right.getOutputSymbols()).containsAll(orderBySymbols) && !isAtMost(right, context.getLookup(), parent.getCount())) {
return Result.ofPlanNode(joinNode.replaceChildren(ImmutableList.of(left, parent.replaceChildren(ImmutableList.of(right)))));
}
return Result.empty();
}
use of io.prestosql.spi.plan.JoinNode in project hetu-core by openlookeng.
the class DynamicFilterService method registerTasksHelper.
private void registerTasksHelper(PlanNode node, Symbol buildSymbol, Map<String, Symbol> dynamicFiltersMap, Set<TaskId> taskIds, Set<InternalNode> workers, StageStateMachine stateMachine) {
final StateStore stateStore = stateStoreProvider.getStateStore();
String queryId = stateMachine.getSession().getQueryId().toString();
for (Map.Entry<String, Symbol> entry : dynamicFiltersMap.entrySet()) {
Symbol buildSymbolToCheck = buildSymbol != null ? buildSymbol : node.getOutputSymbols().contains(entry.getValue()) ? entry.getValue() : null;
if (buildSymbolToCheck != null && entry.getValue().getName().equals(buildSymbol.getName())) {
String filterId = entry.getKey();
stateStore.createStateCollection(createKey(DynamicFilterUtils.TASKSPREFIX, filterId, queryId), SET);
stateStore.createStateCollection(createKey(DynamicFilterUtils.PARTIALPREFIX, filterId, queryId), SET);
dynamicFilters.putIfAbsent(queryId, new ConcurrentHashMap<>());
Map<String, DynamicFilterRegistryInfo> filters = dynamicFilters.get(queryId);
if (node instanceof JoinNode) {
filters.put(filterId, extractDynamicFilterRegistryInfo((JoinNode) node, stateMachine.getSession(), filterId));
} else if (node instanceof SemiJoinNode) {
filters.put(filterId, extractDynamicFilterRegistryInfo((SemiJoinNode) node, stateMachine.getSession()));
}
dynamicFiltersToTask.putIfAbsent(filterId + "-" + queryId, new CopyOnWriteArraySet<>());
CopyOnWriteArraySet<TaskId> taskSet = dynamicFiltersToTask.get(filterId + "-" + queryId);
taskSet.addAll(taskIds);
log.debug("registerTasks source " + filterId + " filters:" + filters + ", workers: " + workers.stream().map(x -> x.getNodeIdentifier()).collect(Collectors.joining(",")) + ", taskIds: " + taskIds.stream().map(TaskId::toString).collect(Collectors.joining(",")));
}
}
}
use of io.prestosql.spi.plan.JoinNode in project hetu-core by openlookeng.
the class CubeOptimizer method parseNodeRecursively.
private void parseNodeRecursively(PlanNode node) {
if (node instanceof ProjectNode) {
ProjectNode projection = ((ProjectNode) node);
validateProjection(projection);
parseNodeRecursively(projection.getSource());
handleProjection(projection);
} else if (node instanceof JoinNode) {
JoinNode localJoinNode = (JoinNode) node;
parseNodeRecursively(localJoinNode.getLeft());
parseNodeRecursively(localJoinNode.getRight());
localJoinNode.getOutputSymbols().stream().map(Symbol::getName).forEach(symbol -> originalPlanMappings.put(symbol, originalPlanMappings.get(symbol)));
localJoinNode.getCriteria().forEach(equiJoinClause -> {
// Join condition(s) must be defined on column from Source table
ColumnWithTable leftColumn = originalPlanMappings.get(equiJoinClause.getLeft().getName());
ColumnWithTable rightColumn = originalPlanMappings.get(equiJoinClause.getRight().getName());
ColumnWithTable sourceTableColumn = leftColumn.getFQTableName().equalsIgnoreCase(sourceTableName) ? leftColumn : rightColumn;
dimensions.add(sourceTableColumn.getColumnName());
groupBy.add(sourceTableColumn.getColumnName());
matchingMetadataList.removeIf(metadata -> {
// Retain Cube metadata, only if one of the join column is part of Cube
return !metadata.getDimensions().contains(sourceTableColumn.getColumnName());
});
});
} else if (node instanceof TableScanNode) {
TableScanNode scanNode = (TableScanNode) node;
TableMetadata tableMetadata = metadata.getTableMetadata(context.getSession(), scanNode.getTable());
scanNode.getOutputSymbols().forEach(output -> {
ColumnWithTable columnWithTable = new ColumnWithTable(tableMetadata.getQualifiedName().toString(), scanNode.getAssignments().get(output).getColumnName());
originalPlanMappings.put(output.getName(), columnWithTable);
});
// Assumption: Cubes are defined on only of the tables involved in Join. That table will be considered Source Table.
List<CubeMetadata> metadataList = cubeMetaStore.getMetadataList(tableMetadata.getQualifiedName().toString());
if (sourceTableScanNode == null && !metadataList.isEmpty()) {
sourceTableScanNode = scanNode;
sourceTableMetadata = tableMetadata;
sourceTableName = sourceTableMetadata.getQualifiedName().toString();
sourceTableHandle = sourceTableScanNode.getTable();
matchingMetadataList.addAll(metadataList);
sourceTableColumnMap.putAll(metadata.getColumnHandles(context.getSession(), sourceTableHandle));
}
} else {
throw new UnsupportedOperationException("Unexpected plan node. Expected TableScan, JoinNode or ProjectNode. Actual is " + node.getClass());
}
}
use of io.prestosql.spi.plan.JoinNode in project hetu-core by openlookeng.
the class OptimizeAggregationOverJoin method apply.
@Override
public Result apply(AggregationNode node, Captures captures, Context context) {
long startOptimizationTime = System.currentTimeMillis();
Optional<PlanNode> preProjectNodeOne = captures.get(OPTIONAL_PRE_PROJECT_ONE);
Optional<PlanNode> preProjectNodeTwo = captures.get(OPTIONAL_PRE_PROJECT_TWO);
List<ProjectNode> projectNodes = new ArrayList<>();
if ((preProjectNodeOne.isPresent() && !(preProjectNodeOne.get() instanceof ProjectNode)) || (preProjectNodeTwo.isPresent() && !(preProjectNodeTwo.get() instanceof ProjectNode))) {
return Result.empty();
}
preProjectNodeOne.map(ProjectNode.class::cast).map(projectNodes::add);
preProjectNodeTwo.map(ProjectNode.class::cast).map(projectNodes::add);
Optional<PlanNode> filterNode = captures.get(OPTIONAL_FILTER);
JoinNode joinNode = (JoinNode) Plans.resolveGroupReferences(captures.get(JOIN_NODE), context.getLookup());
try {
Optional<PlanNode> optimized = CubeOptimizer.forPlan(context, metadata, cubeMetaStore, node, projectNodes, filterNode.map(FilterNode.class::cast).orElse(null), joinNode).optimize();
return optimized.map(Result::ofPlanNode).orElseGet(Result::empty);
} catch (RuntimeException ex) {
LOGGER.warn("Encountered exception '" + ex.getMessage() + "' while applying the CubeOptimizer", ex);
return Result.empty();
} finally {
long endOptimizationTime = System.currentTimeMillis();
LOGGER.debug("Star-tree total optimization time: %d millis", (endOptimizationTime - startOptimizationTime));
}
}
use of io.prestosql.spi.plan.JoinNode in project hetu-core by openlookeng.
the class PushAggregationThroughOuterJoin method coalesceWithNullAggregation.
// When the aggregation is done after the join, there will be a null value that gets aggregated over
// where rows did not exist in the inner table. For some aggregate functions, such as count, the result
// of an aggregation over a single null row is one or zero rather than null. In order to ensure correct results,
// we add a coalesce function with the output of the new outer join and the agggregation performed over a single
// null row.
private Optional<PlanNode> coalesceWithNullAggregation(AggregationNode aggregationNode, PlanNode outerJoin, PlanSymbolAllocator planSymbolAllocator, PlanNodeIdAllocator idAllocator, Lookup lookup) {
// Create an aggregation node over a row of nulls.
Optional<MappedAggregationInfo> aggregationOverNullInfoResultNode = createAggregationOverNull(aggregationNode, planSymbolAllocator, idAllocator, lookup);
if (!aggregationOverNullInfoResultNode.isPresent()) {
return Optional.empty();
}
MappedAggregationInfo aggregationOverNullInfo = aggregationOverNullInfoResultNode.get();
AggregationNode aggregationOverNull = aggregationOverNullInfo.getAggregation();
Map<Symbol, Symbol> sourceAggregationToOverNullMapping = aggregationOverNullInfo.getSymbolMapping();
// Do a cross join with the aggregation over null
JoinNode crossJoin = new JoinNode(idAllocator.getNextId(), JoinNode.Type.INNER, outerJoin, aggregationOverNull, ImmutableList.of(), ImmutableList.<Symbol>builder().addAll(outerJoin.getOutputSymbols()).addAll(aggregationOverNull.getOutputSymbols()).build(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), ImmutableMap.of());
// Add coalesce expressions for all aggregation functions
Assignments.Builder assignmentsBuilder = Assignments.builder();
for (Symbol symbol : outerJoin.getOutputSymbols()) {
if (aggregationNode.getAggregations().containsKey(symbol)) {
assignmentsBuilder.put(symbol, new SpecialForm(COALESCE, planSymbolAllocator.getTypes().get(symbol), ImmutableList.of(toVariableReference(symbol, planSymbolAllocator.getTypes()), toVariableReference(sourceAggregationToOverNullMapping.get(symbol), planSymbolAllocator.getTypes()))));
} else {
assignmentsBuilder.put(symbol, toVariableReference(symbol, planSymbolAllocator.getTypes()));
}
}
return Optional.of(new ProjectNode(idAllocator.getNextId(), crossJoin, assignmentsBuilder.build()));
}
Aggregations