Reputation: 4392
I'm using the Neo4J Traversal API and trying to traverse from "1" to find nodes "2" and "3" fitting the pattern below:
1-[:A]-2-[:B]-3
However, in my traversal, I'm getting caught out because the following relationship also exists:
1-[:B]-3
As far as I understand, my TraversalDescription
needs to specify both relationship types, but I'm unsure of the most elegant way to traverse the :A relationship first, and then branch out to the :B relationship. Unfortunately the relationship Direction
can't be used to differentiate in my case.
My Scala code is:
db.traversalDescription()
.evaluator(isAThenBRelationship)
.breadthFirst()
.relationships(A)
.relationships(B)
private val isAThenBRelationship = new PathEvaluator.Adapter() {
override def evaluate(path: Path, state: BranchState[Nothing]): Evaluation = {
if (path.length == 0) {
EXCLUDE_AND_CONTINUE
} else if (path.length == 1) {
Evaluation.of(false, path.relationships().iterator().next().getType.name() == A.toString)
} else {
Evaluation.of(path.relationships().iterator().next().getType.name() == B.toString, false)
}
}
}
As an aside, what's a better way of comparing relationships than this?
path.relationships().iterator().next().getType.name() == MyRelationship.toString
Upvotes: 2
Views: 425
Reputation: 4392
Additionally to @StefanArmbruster's answer, here's the equivalent Scala code:
db.traversalDescription()
.breadthFirst()
.expand(isAThenBRelationship)
private val isAThenBRelationship =
new PathExpander[Object]() {
override def expand(path: Path, state: BranchState[Object]) =
path.length() match {
case 0 => path.endNode().getRelationships(DynamicRelationshipType.withName("A"))
case 1 => path.endNode().getRelationships(DynamicRelationshipType.withName("B"))
case _ => Iterables.empty()
}
override def reverse(): PathExpander[Object] = ???
}
Note that the expander must come after the relationships.
Upvotes: 1
Reputation: 39915
Using relationships()
multiple times does not imply an order. Instead there is a internal list which relationships()
adds something to.
To limit a certain relationship type to a certain depth, you need to implement and use your own PathExpander
. The example below uses Java and implements the PathExpander
using an anonymous inner class:
traversalDescription.expand(new PathExpander<Object>() {
@Override
public Iterable<Relationship> expand(Path path, BranchState<Object> state) {
switch (path.length()) {
case 0:
return path.endNode().getRelationships(
DynamicRelationshipType.withName("A") );
case 1:
return path.endNode().getRelationships(
DynamicRelationshipType.withName("B") );
default:
return Iterables.empty();
}
}
@Override
public PathExpander<Object> reverse() {
// not used for unidirectional traversals
throw new UnsupportedOperationException();
}
});
Neo4j contains a very convenient class IteratorUtils
. With that your snippet can be written as (assuming MyRelationship is a instance of RelationshipType
:
IteratorUtil.first(path.relationships()).getType().equals(MyRelationship)
Upvotes: 2