Java – directional path in neo4j
I am faced with a seemingly simple problem I want to use the Java API to traverse the nodes of the neo4j graph However, I want to include only paths where all relationships have the same direction If what I do
db.traversalDescription().relationships(<type>,Direction.BOTH)
Path like
[a]-[:TYPE]->[b]<-[:TYPE]-[c]
That's included. I don't want it I just want the path
[a]-[:TYPE]->[b]-[:TYPE]->[c] [a]<-[:TYPE]-[b]<-[:TYPE]-[c]
Can I help you? It seems that the solution should be very simple
Solution
The idea of Wes is introduced in detail In the custom path evaluator, you need to set the branch state to remember the direction of the first relationship All subsequent visits will check whether the last relationship matches the direction In pseudocode:
class SameDirectionPathEvaluator implements PathEvaluator<Direction> { public Evaluation evaluate(Path path,BranchState<Direction> state) { if (path.length()==0) { return Evaluation.EXCLUDE_AND_CONTINUE; } else if (path.length()==1) { state.setState(getDirectionOfLastRelationship(path)); return Evaluation.INCLUDE_AND_CONTINUE; } else { if (state.getState().equals(getDirectionOfLastRelationship(path)) { return Evaluation.INCLUDE_AND_CONTINUE; } else { return Evaluation.EXCLUDE_AND_PRUNE; } } } private Direction getDirectionOfLastRelationship(Path path) { assert path.length() > 0; Direction direction = Direction.INCOMING if (path.endNode().equals(path.lastRelationship().getEndNode()) { direction = Direction.OUTGOING; } return direction; } }
Please note that I did not compile or test the above code - it was just to draft the idea
UPDATE
There seems to be a more effective way to do this Since traversal uses the extender before calling the evaluator, it makes more sense to implement this behavior in the extender:
class ConstantDirectionExpander implements PathExpander<STATE>() { @Override public Iterable<Relationship> expand(Path path,BranchState<STATE> state) { if (path.length()==0) { return path.endNode().getRelationships(types); } else { Direction direction = getDirectionOfLastRelationship(path); return path.endNode().getRelationships(direction,types); } } @Override public PathExpander<STATE> reverse() { return this; } private Direction getDirectionOfLastRelationship(Path path) { assert path.length() > 0; Direction direction = Direction.INCOMING; if (path.endNode().equals(path.lastRelationship().getEndNode())) { direction = Direction.OUTGOING; } return direction; } }
During traversal, you need to use initialbranchsate:
TraversersDescription td = graphDatabaseService.traversalDescriptioin(). .expand(new ConstantDirectionExpander(reltype)) .traverse(startNode)