in asterix-graphix/src/main/java/org/apache/asterix/graphix/lang/rewrite/resolve/ExhaustiveSearchResolver.java [156:243]
private void expandPathPattern(EdgePatternExpr unexpandedPathPattern, Deque<PatternGroup> inputPatternGroups,
Deque<PatternGroup> outputPatternGroups) throws CompilationException {
EdgeDescriptor unexpandedEdgeDescriptor = unexpandedPathPattern.getEdgeDescriptor();
VariableExpr edgeVariable = unexpandedEdgeDescriptor.getVariableExpr();
Set<ElementLabel> edgeLabelSet = unexpandedEdgeDescriptor.getEdgeLabels();
Set<ElementLabel> expandedEdgeLabelSet =
expandElementLabels(unexpandedPathPattern, edgeLabelSet, schemaKnowledgeTable);
// Determine our candidates for internal vertex labels.
Set<ElementLabel> vertexLabelSet = schemaKnowledgeTable.getVertexLabels();
// Determine the direction of our edges.
Set<EdgeDirection> edgeDirectionSet = new HashSet<>();
if (unexpandedEdgeDescriptor.getEdgeDirection() != EdgeDirection.RIGHT_TO_LEFT) {
edgeDirectionSet.add(EdgeDirection.LEFT_TO_RIGHT);
}
if (unexpandedEdgeDescriptor.getEdgeDirection() != EdgeDirection.LEFT_TO_RIGHT) {
edgeDirectionSet.add(EdgeDirection.RIGHT_TO_LEFT);
}
// Determine the length of **expanded** path. For {N,M} w/ E labels... MIN(M, (1 + 2(E-1))).
int minimumExpansionLength, expansionLength;
Integer minimumHops = unexpandedEdgeDescriptor.getMinimumHops();
Integer maximumHops = unexpandedEdgeDescriptor.getMaximumHops();
if (Objects.equals(minimumHops, maximumHops) && minimumHops != null && minimumHops == 1) {
// Special case: we have a path disguised as an edge.
minimumExpansionLength = 1;
expansionLength = 1;
} else {
int maximumExpansionLength = 1 + 2 * (expandedEdgeLabelSet.size() - 1);
minimumExpansionLength = Objects.requireNonNullElse(minimumHops, 1);
expansionLength = Objects.requireNonNullElse(maximumHops, maximumExpansionLength);
if (minimumExpansionLength > expansionLength) {
minimumExpansionLength = expansionLength;
}
}
// Generate all possible paths, from minimumExpansionLength to expansionLength.
List<List<EdgePatternExpr>> candidatePaths = new ArrayList<>();
for (int pathLength = minimumExpansionLength; pathLength <= expansionLength; pathLength++) {
List<List<EdgePatternExpr>> expandedPathPattern = expandFixedPathPattern(pathLength, unexpandedPathPattern,
expandedEdgeLabelSet, vertexLabelSet, edgeDirectionSet, deepCopyVisitor,
() -> deepCopyVisitor.visit(unexpandedPathPattern.getInternalVertex(), null));
candidatePaths.addAll(expandedPathPattern);
}
// Push the labels of our pattern group to our edge.
final BiConsumer<PatternGroup, EdgePatternExpr> vertexLabelUpdater = (p, e) -> {
VariableExpr leftVariable = e.getLeftVertex().getVariableExpr();
VariableExpr rightVariable = e.getRightVertex().getVariableExpr();
p.getVertexPatternSet().forEach(v -> {
VariableExpr vertexVariable = v.getVariableExpr();
if (leftVariable.equals(vertexVariable)) {
e.getLeftVertex().getLabels().clear();
e.getLeftVertex().getLabels().addAll(v.getLabels());
}
if (rightVariable.equals(vertexVariable)) {
e.getRightVertex().getLabels().clear();
e.getRightVertex().getLabels().addAll(v.getLabels());
}
});
};
// Push our expansion to our pattern groups.
while (!inputPatternGroups.isEmpty()) {
PatternGroup unexpandedPatternGroup = inputPatternGroups.pop();
for (List<EdgePatternExpr> candidatePath : candidatePaths) {
PatternGroup expandedPatternGroup = new PatternGroup();
expandedPatternGroup.getVertexPatternSet().addAll(unexpandedPatternGroup.getVertexPatternSet());
for (EdgePatternExpr edgePatternExpr : unexpandedPatternGroup.getEdgePatternSet()) {
if (edgePatternExpr.getEdgeDescriptor().getVariableExpr().equals(edgeVariable)) {
for (EdgePatternExpr candidateEdge : candidatePath) {
EdgePatternExpr copyEdgePattern = deepCopyVisitor.visit(candidateEdge, null);
vertexLabelUpdater.accept(expandedPatternGroup, copyEdgePattern);
expandedPatternGroup.getEdgePatternSet().add(copyEdgePattern);
}
} else {
EdgePatternExpr copyEdgePattern = deepCopyVisitor.visit(edgePatternExpr, null);
vertexLabelUpdater.accept(expandedPatternGroup, copyEdgePattern);
expandedPatternGroup.getEdgePatternSet().add(copyEdgePattern);
}
}
outputPatternGroups.push(expandedPatternGroup);
}
}
}