use of io.confluent.ksql.planner.JoinTree.Leaf in project ksql by confluentinc.
the class LogicalPlanner method buildJoin.
/**
* @param root the root of the Join Tree
* @param prefix the prefix to uniquely identify the plan node
* @return the PlanNode representing this Join Tree
*/
private JoinNode buildJoin(final Join root, final String prefix, final boolean isWindowed) {
final PlanNode preRepartitionLeft;
if (root.getLeft() instanceof JoinTree.Join) {
preRepartitionLeft = buildJoin((Join) root.getLeft(), prefix + "L_", isWindowed);
} else {
final JoinTree.Leaf leaf = (Leaf) root.getLeft();
preRepartitionLeft = new DataSourceNode(new PlanNodeId("KafkaTopic_" + prefix + "Left"), leaf.getSource().getDataSource(), leaf.getSource().getAlias(), isWindowed, ksqlConfig);
}
final PlanNode preRepartitionRight;
if (root.getRight() instanceof JoinTree.Join) {
preRepartitionRight = buildJoin((Join) root.getRight(), prefix + "R_", isWindowed);
} else {
final JoinTree.Leaf leaf = (Leaf) root.getRight();
preRepartitionRight = new DataSourceNode(new PlanNodeId("KafkaTopic_" + prefix + "Right"), leaf.getSource().getDataSource(), leaf.getSource().getAlias(), isWindowed, ksqlConfig);
}
final Optional<Expression> fkExpression = verifyJoin(root.getInfo(), preRepartitionLeft, preRepartitionRight);
final JoinKey joinKey = fkExpression.map(columnReferenceExp -> buildForeignJoinKey(root, fkExpression.get())).orElseGet(() -> buildJoinKey(root));
final PlanNode left = prepareSourceForJoin(root.getLeft(), preRepartitionLeft, prefix + "Left", root.getInfo().getLeftJoinExpression(), fkExpression.isPresent());
final PlanNode right = prepareSourceForJoin(root.getRight(), preRepartitionRight, prefix + "Right", root.getInfo().getRightJoinExpression(), fkExpression.isPresent());
return new JoinNode(new PlanNodeId(prefix + "Join"), root.getInfo().getType(), joinKey.rewriteWith(refRewriter::process), prefix.isEmpty(), left, right, root.getInfo().getWithinExpression(), ksqlConfig.getString(KsqlConfig.KSQL_DEFAULT_KEY_FORMAT_CONFIG));
}
use of io.confluent.ksql.planner.JoinTree.Leaf in project ksql by confluentinc.
the class JoinTreeTest method handlesRightThreeWayJoin.
@Test
public void handlesRightThreeWayJoin() {
// Given:
when(j1.getLeftSource()).thenReturn(a);
when(j1.getRightSource()).thenReturn(b);
when(j2.getLeftSource()).thenReturn(c);
when(j2.getRightSource()).thenReturn(a);
when(j2.flip()).thenReturn(j2);
final List<JoinInfo> joins = ImmutableList.of(j1, j2);
// When:
final Node root = JoinTree.build(joins);
// Then:
assertThat(root, instanceOf(Join.class));
assertThat(root, is(new Join(new Join(new Leaf(a), new Leaf(b), j1), new Leaf(c), j2)));
}
use of io.confluent.ksql.planner.JoinTree.Leaf in project ksql by confluentinc.
the class LogicalPlanner method joinOnNonKeyAttribute.
private static boolean joinOnNonKeyAttribute(final Expression joinExpression, final PlanNode node, final AliasedDataSource aliasedDataSource) {
if (!(joinExpression instanceof ColumnReferenceExp)) {
return true;
}
final ColumnReferenceExp simpleJoinExpression = (ColumnReferenceExp) joinExpression;
final ColumnName joinAttributeName = simpleJoinExpression.getColumnName();
final List<DataSourceNode> dataSourceNodes = node.getSourceNodes().collect(Collectors.toList());
final List<Column> keyColumns;
// n-way join sub-tree (ie, not a leaf)
if (isInnerNode(node)) {
final DataSourceNode qualifiedNode;
if (simpleJoinExpression.maybeQualifier().isPresent()) {
final SourceName qualifierOrAlias = simpleJoinExpression.maybeQualifier().get();
final SourceName qualifier;
if (aliasedDataSource.getAlias().equals(qualifierOrAlias)) {
qualifier = aliasedDataSource.getDataSource().getName();
} else {
qualifier = qualifierOrAlias;
}
final List<DataSourceNode> allNodes = dataSourceNodes.stream().filter(n -> n.getDataSource().getName().equals(qualifier)).collect(Collectors.toList());
if (allNodes.size() != 1) {
throw new KsqlException(String.format("Join qualifier '%s' could not be resolved (either not found or not unique).", qualifier));
}
qualifiedNode = Iterables.getOnlyElement(allNodes);
} else {
final List<DataSourceNode> allNodes = dataSourceNodes.stream().filter(n -> n.getSchema().findColumn(simpleJoinExpression.getColumnName()).isPresent()).collect(Collectors.toList());
if (allNodes.size() != 1) {
throw new KsqlException(String.format("Join identifier '%s' could not be resolved (either not found or not unique).", joinAttributeName));
}
qualifiedNode = Iterables.getOnlyElement(allNodes);
}
keyColumns = qualifiedNode.getSchema().key();
} else {
// leaf node: we know we have single data source
keyColumns = Iterables.getOnlyElement(dataSourceNodes).getSchema().key();
}
// - thus, if the key has more than one column, the join is not on the key
if (keyColumns.size() > 1) {
return true;
}
return !joinAttributeName.equals(Iterables.getOnlyElement(keyColumns).name());
}
use of io.confluent.ksql.planner.JoinTree.Leaf in project ksql by confluentinc.
the class JoinTreeTest method handlesLeftThreeWayJoin.
@Test
public void handlesLeftThreeWayJoin() {
// Given:
when(j1.getLeftSource()).thenReturn(a);
when(j1.getRightSource()).thenReturn(b);
when(j2.getLeftSource()).thenReturn(a);
when(j2.getRightSource()).thenReturn(c);
final List<JoinInfo> joins = ImmutableList.of(j1, j2);
// When:
final Node root = JoinTree.build(joins);
// Then:
assertThat(root, instanceOf(Join.class));
assertThat(root, is(new Join(new Join(new Leaf(a), new Leaf(b), j1), new Leaf(c), j2)));
}
Aggregations