// add new operators...
Join join_new = new lupos.engine.operators.multiinput.join.Join();
join_new.setIntersectionVariables(join1.getIntersectionVariables());
join_new.setUnionVariables(union1.getUnionVariables());
Union union_new = new lupos.engine.operators.multiinput.Union();
union_new.setIntersectionVariables(union1.getIntersectionVariables());
union_new.setUnionVariables(union1.getUnionVariables());
int countingUnions = 0;
firstLoop: for (;;) {
// for each 1st sg container
for (BasicOperator prec : union1.getPrecedingOperators()) {
boolean match = false;
// find the matching second one
for (BasicOperator prec2 : union2.getPrecedingOperators()) {
if (!compareBothSubgraphContainer((SubgraphContainer) prec,
(SubgraphContainer) prec2))
continue;
match = true;
/*
* store with better variable name
*/
SubgraphContainer sg1 = (SubgraphContainer) prec;
SubgraphContainer sg2 = (SubgraphContainer) prec2;
// remove succedding UNION-operator for both subgraphs
for (OperatorIDTuple eachSucc : prec
.getSucceedingOperators()) {
prec.removeSucceedingOperator(eachSucc);
eachSucc.getOperator().removePrecedingOperator(prec);
}
for (OperatorIDTuple eachSucc : prec2
.getSucceedingOperators()) {
prec2.removeSucceedingOperator(eachSucc);
eachSucc.getOperator().removePrecedingOperator(prec2);
}
// remove 2nd sg
for (BasicOperator bo : sg2.getPrecedingOperators()) {
bo.removeSucceedingOperator(sg2);
sg2.removePrecedingOperator(bo);
}
/*
* join with is to be included into the subgraph container
*/
Join smallJoin = new Join();
smallJoin.cloneFrom(join_new);
// remove so that the for-loop will end!
union1.removePrecedingOperator(prec);
union2.removePrecedingOperator(prec2);
/*
* get the index scan in first subgraph
*/
BasicIndexScan bis = getIndexScan(sg1.getRootOfSubgraph());
if (bis == null)
continue;
/*
* you have to clone this list, because if changing
* something, the list is updated immediately, but we want
* to access the removed items later!
*/
List<OperatorIDTuple> _bisSucc = bis
.getSucceedingOperators();
List<OperatorIDTuple> bisSucc = new ArrayList<>(
_bisSucc.size());
for (OperatorIDTuple toClone : _bisSucc) {
bisSucc.add(toClone);
}
/*
* now add the 2nd subgraph container in the first subgraph
* container
*/
sg1.getRootOfSubgraph().addSucceedingOperator(sg2);
/*
* remove old connections of the 2nd subgraph (because it
* should be included into the subgraph)
*/
for (OperatorIDTuple op : bisSucc) {
bis.removeSucceedingOperator(op);
op.getOperator().removePrecedingOperator(bis);
}
/*
* connect the basic index scan and the 2nd subgraph
* container in the join-operator in the 1st subgraph
* container
*/
bis.addSucceedingOperator(smallJoin, 0);
smallJoin.addPrecedingOperator(sg2);
sg2.addSucceedingOperator(smallJoin, 1);
smallJoin.addPrecedingOperator(bis);
/*
* now connect the join with the succeeding operators of the
* old basic index scan (here we use the hack, to clone the
* succeeding list of the index scan, because when we
* removed the connection and added the join, the list would
* have no content)
*/
for (OperatorIDTuple op : bisSucc) {
smallJoin.addSucceedingOperator(op);
op.getOperator().addPrecedingOperator(smallJoin);
}
/*
* now connect the UNION with the result of the 1st subgraph
* container. In this UNION all partitions are to be
* combined.
*/
union_new.addPrecedingOperator(sg1);
OperatorIDTuple unionIDOperator = new OperatorIDTuple(
union_new, countingUnions++);
sg1.addSucceedingOperator(unionIDOperator);
/*
* this is to be executed, if the 2nd subgraph is directly
* added as succeeding of the root, because in this case,
* the 2nd subgraph container has no preceding (i don't know
* why this is done this way)
*/
if (this.root != null) {
this.root.removeSucceedingOperator(sg2);
}
/*
* add the intersections variables of the 2nd sg to the
* first one
*/
Collection<Variable> sg1interSection = sg1
.getIntersectionVariables();
Collection<Variable> sg2interSection = sg2
.getIntersectionVariables();
if (sg1interSection == null)
sg1interSection = new HashSet<>();
if (sg2interSection != null)
sg1interSection.addAll(sg2interSection);
sg1.setIntersectionVariables(sg1interSection);
/*
* add the union variables of the 2nd sg to the first one
*/
Collection<Variable> sg1union = sg1.getUnionVariables();
Collection<Variable> sg2union = sg2.getUnionVariables();
if (sg1union == null)
sg1union = new HashSet<>();
if (sg2union != null)
sg1union.addAll(sg2union);
sg1.setUnionVariables(sg1union);
log.debug(String.format(
"Rule %s: Local join between %s and %s in %s",
this.ruleName, sg1, sg2, sg1));
continue firstLoop;
}
/*
* we have no match -> no partitions which can be used for local
* join -> exit!
*/
if (!match)
return;
}
break;
}
/*
* stuff from the rule builder ...
*/
// remove obsolete connections...
this.union1.removeSucceedingOperator(this.join1);
this.join1.removePrecedingOperator(this.union1);
// remove all connections to the follower of our processing tree
// and add the new union
List<OperatorIDTuple> succeddingsOfAll = this.join1
.getSucceedingOperators();
for (OperatorIDTuple _child : succeddingsOfAll) {
_child.getOperator().removePrecedingOperator(this.join1);
union_new.addSucceedingOperator(_child);
_child.getOperator().addPrecedingOperator(union_new);
}
// delete unreachable operators...
this.deleteOperatorWithoutParentsRecursive(this.join1, _startNodes);
this.deleteOperatorWithoutParentsRecursive(this.union1, _startNodes);