Directed paths in Neo4j

java, neo4j

Solution

Detailing Wes' idea a little bit. In your custom `PathEvaluator` you need to set branch state to remember the direction of the first relationship. All subsequent visits check if the last relationship matches the direction. In pseudo code:

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 I did not compile or test the code above - it's just for sketching the idea.

UPDATE

It seems there is a more efficient way to do this. Since traversals use expanders before evaluators are invoked it makes more sense to implement this behaviour in an expander:

     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;
        }
    }

In your traversal you need use a `InitialBranchSate`:

TraversersDescription td = graphDatabaseService.traversalDescriptioin().
  .expand(new ConstantDirectionExpander(reltype))
  .traverse(startNode)

Problem

I am facing a seemingly simple issue. I want to traverse the nodes of a `Neo4j` graph, using the traversal Java API. I want to include only paths where all relationships have the same direction, though. If I do something like ``` db.traversalDescription().relationships(<type>, Direction.BOTH) ``` paths like ``` [a]-[:TYPE]->[b]<-[:TYPE]-[c] ``` are included as well which I don't want. I only want paths like ``` [a]-[:TYPE]->[b]-[:TYPE]->[c] [a]<-[:TYPE]-[b]<-[:TYPE]-[c] ``` Can anybody help? It seems like the solution should be quite simple.

Original source