in gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathProcessorStrategy.java [90:188]
public void apply(final Traversal.Admin<?, ?> traversal) {
// using a hidden label marker to denote whether the traversal should not be processed by this strategy
if ((traversal.getParent() instanceof EmptyStep || traversal.getParent() instanceof VertexProgramStep) &&
TraversalHelper.hasStepOfAssignableClassRecursively(INVALIDATING_STEP_CLASSES, traversal))
TraversalHelper.applyTraversalRecursively(t -> t.getStartStep().addLabel(MARKER), traversal);
if (traversal.getStartStep().getLabels().contains(MARKER)) {
traversal.getStartStep().removeLabel(MARKER);
return;
}
// process where(as("a").out()...) => select("a").where(out()...)
final List<WhereTraversalStep> whereTraversalSteps = TraversalHelper.getStepsOfClass(WhereTraversalStep.class, traversal);
for (final WhereTraversalStep<?> whereTraversalStep : whereTraversalSteps) {
final Traversal.Admin<?, ?> localChild = whereTraversalStep.getLocalChildren().get(0);
if ((localChild.getStartStep() instanceof WhereTraversalStep.WhereStartStep) &&
!((WhereTraversalStep.WhereStartStep) localChild.getStartStep()).getScopeKeys().isEmpty()) {
boolean done = false;
while (!done) {
done = true;
final int index = TraversalHelper.stepIndex(whereTraversalStep, traversal);
if (whereTraversalStep.getPreviousStep() instanceof SelectStep) {
done = false;
traversal.removeStep(index);
traversal.addStep(index - 1, whereTraversalStep);
}
}
final WhereTraversalStep.WhereStartStep<?> whereStartStep = (WhereTraversalStep.WhereStartStep<?>) localChild.getStartStep();
int index = TraversalHelper.stepIndex(whereTraversalStep, traversal);
final SelectOneStep<?, ?> selectOneStep = new SelectOneStep<>(traversal, Pop.last, whereStartStep.getScopeKeys().iterator().next());
traversal.addStep(index, selectOneStep);
final String generatedLabel = generateLabel(whereStartStep);
if (selectOneStep.getPreviousStep() instanceof EmptyStep) {
TraversalHelper.insertBeforeStep(new IdentityStep<>(traversal), selectOneStep, traversal);
index++;
}
selectOneStep.getPreviousStep().addLabel(generatedLabel);
TraversalHelper.insertAfterStep(new SelectOneStep<>(traversal, Pop.last, generatedLabel), whereTraversalStep, traversal);
whereStartStep.removeScopeKey();
// process where(as("a").out()) => as('xyz').select("a").filter(out()).select('xyz')
if (!(localChild.getEndStep() instanceof WhereTraversalStep.WhereEndStep)) {
localChild.removeStep(localChild.getStartStep());
traversal.addStep(index + 1, new TraversalFilterStep<>(traversal, localChild));
traversal.removeStep(whereTraversalStep);
}
}
}
// process select("a","b").by(...).by(...)
final List<SelectStep> selectSteps = TraversalHelper.getStepsOfClass(SelectStep.class, traversal);
for (final SelectStep<?, Object> selectStep : selectSteps) {
if (selectStep.getPop() != Pop.all && selectStep.getPop() != Pop.mixed && // TODO: necessary?
selectStep.getMaxRequirement().compareTo(PathProcessor.ElementRequirement.ID) > 0) {
boolean oneLabel = true;
for (final String key : selectStep.getScopeKeys()) {
if (labelCount(key, TraversalHelper.getRootTraversal(traversal)) > 1) {
oneLabel = false;
break;
}
}
if (!oneLabel)
continue;
final int index = TraversalHelper.stepIndex(selectStep, traversal);
final Map<String, Traversal.Admin<Object, Object>> byTraversals = selectStep.getByTraversals();
final String[] keys = new String[byTraversals.size()];
int counter = 0;
for (final Map.Entry<String, Traversal.Admin<Object, Object>> entry : byTraversals.entrySet()) {
final SelectOneStep selectOneStep = new SelectOneStep(traversal, selectStep.getPop(), entry.getKey());
final TraversalMapStep<?, ?> mapStep = new TraversalMapStep<>(traversal, entry.getValue().clone());
mapStep.addLabel(entry.getKey());
traversal.addStep(index + 1, mapStep);
traversal.addStep(index + 1, selectOneStep);
keys[counter++] = entry.getKey();
}
traversal.addStep(index + 1 + (byTraversals.size() * 2), new SelectStep(traversal, Pop.last, keys));
traversal.removeStep(index);
}
}
// process select("a").by(...)
//
// unfortunately, this strategy needs to know about ProductiveByStrategy. the ordering of strategies
// doesn't have enough flexibility to handle this situation where ProductiveByStrategy can run prior
// to this but also after ByModulatorOptimizationStrategy.
if (!traversal.getStrategies().getStrategy(ProductiveByStrategy.class).isPresent()) {
final List<SelectOneStep> selectOneSteps = TraversalHelper.getStepsOfClass(SelectOneStep.class, traversal);
for (final SelectOneStep<?, ?> selectOneStep : selectOneSteps) {
if (selectOneStep.getPop() != Pop.all && selectOneStep.getPop() != Pop.mixed && // TODO: necessary?
selectOneStep.getMaxRequirement().compareTo(PathProcessor.ElementRequirement.ID) > 0 &&
labelCount(selectOneStep.getScopeKeys().iterator().next(), TraversalHelper.getRootTraversal(traversal)) <= 1) {
final int index = TraversalHelper.stepIndex(selectOneStep, traversal);
final Traversal.Admin<?, ?> localChild = selectOneStep.getLocalChildren().get(0);
selectOneStep.removeLocalChild(localChild);
final TraversalMapStep<?, ?> mapStep = new TraversalMapStep<>(traversal, localChild.clone());
traversal.addStep(index + 1, mapStep);
}
}
}
}