Question

I'm new to Neo4j, but I spent some time reading the documentation. I think I understand the base concepts, and I'm now pretty confident with Cypher queries. Though, I have problems understanding how the Traversal API works (well, I don't get expected result, so I guess I'm doing something wrong).

Here's my (very) simple model (created with the API) :

  Node sugar = graphDb.createNode(LabelType.RAW_MATERIAL.getLabel());
  sugar.setProperty(PropertyType.NAME.getName(), "Sugar");
  Node caramel = graphDb.createNode(LabelType.RAW_MATERIAL.getLabel(), LabelType.COOKED_MEAL.getLabel());
  caramel.setProperty(PropertyType.NAME.getName(), "Caramel");

  caramel.createRelationshipTo(sugar, FoodRelationshipType.CONTAINS);

What I want to achieve is to get all the nodes that "Caramel" :CONTAINS. I can do that with a cipher query :

MATCH (:CookedMeal {name: 'Caramel'}) - [:CONTAINS] -> (rawMaterials)  return rawMaterials

In Java, I did the following, without any success (because it returns only the nodes I pass to the "traverse()" method) :

  TraversalDescription traversalDescription = graphDb.traversalDescription()
        .depthFirst()
        .relationships(FoodRelationshipType.CONTAINS, Direction.INCOMING);

  Traverser traverser = traversalDescription.traverse(
        Iterables.toArray(GlobalGraphOperations.at(graphDb).getAllNodesWithLabel(LabelType.COOKED_MEAL.getLabel()), Node.class)
  );

  for (Path path : traverser) {
      System.out.println(path.endNode());
  }

It's like the query doesn't use the traversal relationships() method. Any idea why this doesn't work?

Was it helpful?

Solution

I found the solution to my problem :

TraversalDescription must be given info about what to do from the starting node, not to the target node. For instance, if I got A - [:REL] -> B and start from A, I must indicate an OUTGOING direction for the relation.

This seems not user friendly for me, as it's unlike filters, which I though it was.

Furthermore, I needed to add .evaluator(Evaluators.excludeStartPosition()) to exclude the initial node from the result.

I don't know if the explication is clear enough, but here's a working code :

/**
 * Find components of Caramel : tests that level 1 relationship works
 */
@Test
public void testCaramelContainsSugar() {
    try (Transaction ignored = graphDb.beginTx()) {

        Node n = null;
        TraversalDescription traversalDescription = graphDb.traversalDescription()
                .breadthFirst()
                .relationships(FoodRelationshipType.CONTAINS, Direction.OUTGOING)
                .evaluator(Evaluators.excludeStartPosition());

        Traverser traverser = traversalDescription.traverse(
                getSingleNode(LabelType.COOKED_MEAL, PropertyType.NAME.getName(), "Caramel")
        );

        List<Node> endNodes = new ArrayList<>();
        for (Path path : traverser) {
            endNodes.add(path.endNode());
        }

        Assert.assertTrue(endNodes.contains(getSingleNode(LabelType.RAW_MATERIAL, PropertyType.NAME.getName(), "Sugar")));
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top