/**
  * returns a traverser for all nodes that have a hero relationship and are connected to the hero
  * collection node
  *
  * @return
  */
 private Traverser getHeroesByCollectionNodeViaRest() {
   TraversalDescription td =
       RestTraversal.description()
           .maxDepth(10)
           .breadthFirst()
           .relationships(RelTypes.HERO, Direction.OUTGOING);
   return td.traverse(this.restmdg.getHeroesCollectionNode());
 }
 /**
  * returns a traverser for all nodes that have an outgoing relationship of the type KNOWS
  *
  * @param person the startnode
  * @return the Traverser
  */
 private static Traverser getFriends(final Node person) {
   TraversalDescription td =
       RestTraversal.description()
           .maxDepth(10)
           .breadthFirst()
           .relationships(RelTypes.KNOWS, Direction.OUTGOING)
           .filter(Traversal.returnAllButStartNode());
   return td.traverse(person);
 }
Пример #3
0
 public Iterable<Node> getAllIndexInternalNodes() {
   TraversalDescription td =
       database
           .traversalDescription()
           .breadthFirst()
           .relationships(RTreeRelationshipTypes.RTREE_CHILD, Direction.OUTGOING)
           .evaluator(Evaluators.excludeStartPosition());
   return td.traverse(getIndexRoot()).nodes();
 }
Пример #4
0
  public String createPagedTraverser(
      long nodeId, Map<String, Object> description, int pageSize, int leaseTime) {
    Node node = graphDb.getNodeById(nodeId);

    TraversalDescription traversalDescription = TraversalDescriptionBuilder.from(description);

    PagedTraverser traverser = new PagedTraverser(traversalDescription.traverse(node), pageSize);

    return leases.createLease(leaseTime, traverser).getId();
  }
 @Test
 public void testTraverseToNeighbour() {
   final Relationship rel = relationship();
   final TraversalDescription traversalDescription =
       RestTraversal.description().maxDepth(1).breadthFirst();
   System.out.println("traversalDescription = " + traversalDescription);
   final Traverser traverser = traversalDescription.traverse(rel.getStartNode());
   final Iterable<Node> nodes = traverser.nodes();
   Assert.assertEquals(rel.getEndNode(), nodes.iterator().next());
 }
 /**
  * returns a traverser for all nodes that have an outgoing relationship of the type HERO an are 3
  * positions down in the path
  *
  * @return the Traverser
  */
 private Traverser getHeroesViaRest() {
   TraversalDescription td =
       RestTraversal.description()
           .maxDepth(3)
           .breadthFirst()
           .relationships(RelTypes.PERSONS_REFERENCE, Direction.OUTGOING)
           .relationships(RelTypes.HEROES_REFERENCE, Direction.OUTGOING)
           .relationships(RelTypes.HERO, Direction.OUTGOING)
           .filter(ScriptLanguage.JAVASCRIPT, "position.length() == 3;");
   return td.traverse(this.restmdg.getGraphDatabase().getReferenceNode());
 }
Пример #7
0
 private void checkGeometryNodeIterator() {
   TraversalDescription td =
       database
           .traversalDescription()
           .depthFirst()
           .relationships(RTreeRelationshipTypes.RTREE_REFERENCE, Direction.OUTGOING)
           .evaluator(Evaluators.excludeStartPosition())
           .evaluator(Evaluators.toDepth(1));
   while ((geometryNodeIterator == null || !geometryNodeIterator.hasNext())
       && allIndexNodeIterator.hasNext()) {
     geometryNodeIterator = td.traverse(allIndexNodeIterator.next()).nodes().iterator();
   }
 }
Пример #8
0
  @Test
  public void testNarrowingFilters() {
    Evaluator mustBeConnectedToK = new MustBeConnectedToNodeFilter(getNodeWithName("k"));
    Evaluator mustNotHaveMoreThanTwoOutRels =
        new Evaluator() {
          public Evaluation evaluate(Path path) {
            return Evaluation.ofIncludes(
                count(path.endNode().getRelationships(Direction.OUTGOING)) <= 2);
          }
        };

    TraversalDescription description = traversal().evaluator(mustBeConnectedToK);
    expectNodes(description.traverse(node("a")), "b", "c");
    expectNodes(description.evaluator(mustNotHaveMoreThanTwoOutRels).traverse(node("a")), "c");
  }
 /**
  * returns a traverser for all nodes that have a property type == hero in the embedded Database
  *
  * @return the Traverser
  */
 private Traverser getHeroesByNodeProperties() {
   TraversalDescription td =
       Traversal.description()
           .breadthFirst()
           .relationships(RelTypes.PERSONS_REFERENCE, Direction.OUTGOING)
           .relationships(RelTypes.HEROES_REFERENCE, Direction.OUTGOING)
           .relationships(RelTypes.HERO, Direction.OUTGOING)
           .filter(
               new Predicate<Path>() {
                 public boolean accept(Path path) {
                   return path.endNode().getProperty("type", "none").equals("hero");
                 }
               });
   return td.traverse(this.embeddedmdg.getGraphDatabase().getReferenceNode());
 }
  // ----- private methods -----
  private Path getValidatedPath() throws FrameworkException {

    // the nodes we want to find an existing path for.
    Node startNode = firstResource.getTypesafeNode().getNode();
    Node endNode = lastResource.getTypesafeNode().getNode();

    // set desired path length we want to get
    pathLength = idSet.size();

    // traversal should return exactly one path
    Map<Integer, Path> paths = new HashMap<Integer, Path>();

    for (Iterator<Path> it = traversalDescription.traverse(startNode).iterator(); it.hasNext(); ) {

      Path path = it.next();

      // iterate
      for (Node node : path.nodes()) {}

      paths.put(path.length(), path);
    }

    Path path = paths.get(pathLength - 1);
    if ((path != null) && path.startNode().equals(startNode) && path.endNode().equals(endNode)) {
      return path;
    }

    return null;
  }
Пример #11
0
  public ListRepresentation traverse(
      long startNode, Map<String, Object> description, TraverserReturnType returnType) {
    Node node = graphDb.getNodeById(startNode);

    List<Representation> result = new ArrayList<Representation>();

    TraversalDescription traversalDescription = TraversalDescriptionBuilder.from(description);
    for (Path position : traversalDescription.traverse(node)) {
      MappingRepresentation representation = returnType.toRepresentation(position);
      if (representation != null) {
        result.add(representation);
      }
    }

    return new ListRepresentation(returnType.repType, result);
  }
  private void testNodesAreReturnedOnceWhenSufficientRecentlyUnique(
      TraversalDescription description) {
    Traverser traverser =
        description.uniqueness(Uniqueness.NODE_RECENT, 6).traverse(referenceNode());

    expectNodes(traverser, "1", "2", "3", "4", "5", "6");
  }
Пример #13
0
 public SearchResults searchIndex(SearchFilter filter) {
   try (Transaction tx = database.beginTx()) {
     SearchEvaluator searchEvaluator = new SearchEvaluator(filter);
     TraversalDescription td =
         database
             .traversalDescription()
             .depthFirst()
             .relationships(RTreeRelationshipTypes.RTREE_CHILD, Direction.OUTGOING)
             .relationships(RTreeRelationshipTypes.RTREE_REFERENCE, Direction.OUTGOING)
             .evaluator(searchEvaluator);
     Traverser traverser = td.traverse(getIndexRoot());
     SearchResults results = new SearchResults(traverser.nodes());
     tx.success();
     return results;
   }
 }
  public void addTypedIdResource(TypedIdResource typedIdResource) throws FrameworkException {

    logger.log(Level.FINE, "Adding id {0} to id set", typedIdResource.getIdResource().getUriPart());

    // we need to differentiate between UuidResource and UuidResource
    UuidResource idResource = typedIdResource.getIdResource();

    if (idResource instanceof UuidResource) {

      // add uuid from TypedIdResource to idSet
      if (!idSet.add(((UuidResource) idResource).getUriPart())) {

        // id alread in set, this is an illegal path!
        throw new IllegalPathException();
      }
    } else {

      // add id from TypedIdResource to idSet
      if (!idSet.add(idResource.getUuid())) {

        // id alread in set, this is an illegal path!
        throw new IllegalPathException();
      }
    }

    // add id from TypedIdResource to idSet

    uriParts.add(typedIdResource.getUriPart());

    // find static relationship between the two types
    PropertyKey key = findPropertyKey(lastResource, typedIdResource.getTypeResource());
    if (key != null && key instanceof AbstractRelationProperty) {

      AbstractRelationProperty rel = (AbstractRelationProperty) key;

      if (!visitedRelationships.contains(rel)) {

        traversalDescription =
            traversalDescription.relationships(rel.getRelType(), rel.getDirection());
        visitedRelationships.add(rel);
      }

    } else {

      String rawType1 = lastResource.getTypeResource().getRawType();
      String rawType2 = typedIdResource.getTypeResource().getRawType();

      logger.log(
          Level.INFO,
          "No relationship defined between {0} and {1}, illegal path",
          new Object[] {rawType1, rawType2});

      // no relationship defined, illegal path
      throw new IllegalPathException();
    }

    // store last constraint separately
    lastResource = typedIdResource;
  }
  private void testRelationshipsAreReturnedOnceWhenSufficientRecentlyUnique(
      TraversalDescription description) throws Exception {
    Traverser traverser =
        description
            .uniqueness(Uniqueness.RELATIONSHIP_RECENT, THE_WORLD_AS_WE_KNOW_IT.length)
            .traverse(referenceNode());

    expectRelationships(traverser, THE_WORLD_AS_WE_KNOW_IT);
  }
  private void canPreFilterNodes(TraversalDescription description) {
    Traverser traverser =
        description
            .uniqueness(Uniqueness.NONE)
            .evaluator(Evaluators.atDepth(2))
            .traverse(referenceNode());

    expectPaths(traverser, "1,2,6", "1,3,5", "1,4,5", "1,5,3", "1,5,4", "1,5,6");
  }
  private void canPruneTraversalAtSpecificDepth(TraversalDescription description) {
    Traverser traverser =
        description
            .uniqueness(Uniqueness.NONE)
            .evaluator(Evaluators.toDepth(1))
            .traverse(referenceNode());

    expectNodes(traverser, "1", "2", "3", "4", "5");
  }
Пример #18
0
  @Override
  public TraversalDescription getTraversalDescription(final SecurityContext securityContext) {

    TraversalDescription description =
        StructrApp.getInstance(securityContext)
            .getGraphDatabaseService()
            .traversalDescription()
            .breadthFirst()
            .uniqueness(getUniqueness());

    // set evaluators
    for (Evaluator evaluator : getEvaluators()) {
      description = description.evaluator(evaluator);
    }

    // add predicates as evaluators
    for (final Predicate<Node> predicate : predicates) {
      description =
          description.evaluator(
              new Evaluator() {

                @Override
                public Evaluation evaluate(Path path) {
                  Node endNode = path.endNode();
                  if (predicate.evaluate(securityContext, endNode)) {
                    return Evaluation.EXCLUDE_AND_PRUNE;
                  }

                  return Evaluation.INCLUDE_AND_CONTINUE;
                }
              });
    }

    // set rel type and direction
    int numRels = relTypes.size();
    for (int i = 0; i < numRels; i++) {
      RelationshipType relType = relTypes.get(i);
      Direction direction = directions.get(i);
      description = description.relationships(relType, direction);
    }

    return description;
  }
  private void testAllUniqueRelationshipPathsAreReturned(TraversalDescription description)
      throws Exception {
    Set<String> expected = new HashSet<String>(Arrays.asList(NODE_UNIQUE_PATHS));
    expected.addAll(Arrays.asList(RELATIONSHIP_UNIQUE_EXTRA_PATHS));

    Traverser traverser =
        description.uniqueness(Uniqueness.RELATIONSHIP_PATH).traverse(referenceNode());

    expectPaths(traverser, expected);
  }
Пример #20
0
 @Test
 public void getAllGroups() throws Exception {
   Transaction tx = graphDb.beginTx();
   try {
     System.out.println("All groups:");
     // START SNIPPET: get-groups
     Node referenceNode = graphDb.getReferenceNode();
     TraversalDescription td =
         Traversal.description()
             .breadthFirst()
             .relationships(RoleRels.ROOT, Direction.INCOMING)
             .relationships(RoleRels.PART_OF, Direction.INCOMING)
             .evaluator(Evaluators.excludeStartPosition());
     for (Node group : td.traverse(referenceNode).nodes()) {
       System.out.println(group.getProperty(NAME));
     }
     // END SNIPPET: get-groups
     tx.success();
   } finally {
     tx.finish();
   }
 }
  @Override
  protected Traverser instantiateTraverser(Node start, Node end) {
    TraversalDescription side =
        traversal()
            .breadthFirst()
            .expand(expander)
            .uniqueness(RELATIONSHIP_GLOBAL)
            .order(
                new BranchOrderingPolicy() {
                  public BranchSelector create(TraversalBranch startSource, PathExpander expander) {
                    return new LiteDepthFirstSelector(startSource, startThreshold, expander);
                  }
                });

    return bidirectionalTraversal()
        .startSide(side.evaluator(toDepth(onDepth / 2)))
        .endSide(side.evaluator(toDepth(onDepth - onDepth / 2)))
        .collisionEvaluator(atDepth(onDepth))
        // TODO Level side selector will make the traversal return wrong result, why?
        //                .sideSelector( SideSelectorPolicies.LEVEL, onDepth )
        .traverse(start, end);
  }
Пример #22
0
 @Test
 public void getJalesMemberships() throws Exception {
   Transaction tx = graphDb.beginTx();
   try {
     System.out.println("Jale's memberships:");
     // START SNIPPET: get-user-memberships
     Node jale = getUserByName("Jale");
     TraversalDescription td =
         Traversal.description()
             .depthFirst()
             .relationships(RoleRels.MEMBER_OF, Direction.OUTGOING)
             .relationships(RoleRels.PART_OF, Direction.OUTGOING)
             .evaluator(Evaluators.excludeStartPosition());
     for (Path path : td.traverse(jale)) {
       Node membership = path.endNode();
       System.out.println(membership.getProperty(NAME) + " " + (path.length() - 1));
     }
     // END SNIPPET: get-user-memberships
     tx.success();
   } finally {
     tx.finish();
   }
 }
Пример #23
0
 @Test
 public void getAllAdmins() {
   Transaction tx = graphDb.beginTx();
   try {
     System.out.println("All admins:");
     // START SNIPPET: get-admins
     Node admins = getGroupByName("Admins");
     TraversalDescription td =
         Traversal.description()
             .breadthFirst()
             .relationships(RoleRels.PART_OF, Direction.INCOMING)
             .relationships(RoleRels.MEMBER_OF, Direction.INCOMING)
             .evaluator(Evaluators.excludeStartPosition());
     for (Path path : td.traverse(admins)) {
       Node part = path.endNode();
       System.out.println(part.getProperty(NAME) + " " + (path.length() - 1));
     }
     // END SNIPPET: get-admins
     tx.success();
   } finally {
     tx.finish();
   }
 }
Пример #24
0
  public String getGroups(@Name("filter") String filter) {
    StringWriter resultWriter = new StringWriter();
    JsonFactory f = new JsonFactory();
    f.setCodec(om);
    JsonGenerator g;
    try {
      g = f.createGenerator(resultWriter);

      final Node target = DB.getIndex().get("id", "agents").getSingle();
      TraversalDescription td =
          Traversal.description()
              .relationships(RelTypes.SUBGROUP, Direction.OUTGOING)
              .uniqueness(Uniqueness.NODE_PATH);

      Traverser results = td.traverse(target);
      g.writeStartArray();
      Iterator<Path> paths = results.iterator();
      while (paths.hasNext()) {
        Path path = paths.next();
        if (!path.endNode().hasProperty("name")) continue;
        g.writeStartObject();
        g.writeStringField("name", (String) path.endNode().getProperty("name"));
        g.writeArrayFieldStart("path");
        for (Node pathStep : path.nodes()) {
          if (pathStep.hasProperty("name")) g.writeString((String) pathStep.getProperty("name"));
        }
        g.writeEndArray();
        g.writeEndObject();
      }
      g.writeEndArray();
      g.flush();
    } catch (IOException e) {
      e.printStackTrace();
    }
    resultWriter.flush();
    return resultWriter.toString();
  }
Пример #25
0
  public Iterable<WeightedPath> findAllPaths(Node start, final Node end) {
    lastTraverser =
        TRAVERSAL
            .expand(expander, stateFactory)
            .order(new SelectorFactory(costEvaluator))
            .evaluator(Evaluators.includeWhereEndNodeIs(end))
            .traverse(start);

    // Here's how the bidirectional equivalent would look
    //        lastTraverser = Traversal.bidirectionalTraversal()
    //                .mirroredSides( TRAVERSAL.expand( expander ).order( new SelectorFactory(
    // costEvaluator ) ) )
    //                .traverse( start, end );

    return new Iterable<WeightedPath>() {
      public Iterator<WeightedPath> iterator() {
        return new StopAfterWeightIterator(lastTraverser.iterator(), costEvaluator);
      }
    };
  }
  public RelationshipFollowingResource(
      SecurityContext securityContext, TypedIdResource typedIdResource) {

    this.traversalDescription =
        Traversal.description()
            .depthFirst()
            .uniqueness(Uniqueness.NODE_GLOBAL)
            .evaluator(Evaluators.excludeStartPosition());
    this.visitedRelationships = new LinkedHashSet<AbstractRelationProperty>();
    this.securityContext = securityContext;
    this.idSet = new LinkedHashSet<Object>();
    this.uriParts = new LinkedList<String>();

    // add TypedIdResource to list of evaluators
    traversalDescription = traversalDescription.evaluator(this);

    // store first and last constraint separately
    // to be able to access them faster afterwards
    firstResource = typedIdResource;
    lastResource = typedIdResource;

    UuidResource idResource = typedIdResource.getIdResource();

    if (idResource instanceof UuidResource) {

      logger.log(Level.FINE, "Adding id {0} to id set", idResource.getUriPart());

      // add uuid from TypedIdResource to idSet
      idSet.add(((UuidResource) idResource).getUriPart());

    } else {

      logger.log(Level.FINE, "Adding id {0} to id set", idResource.getUriPart());

      // add id from TypedIdResource to idSet
      idSet.add(idResource.getUuid());
    }
  }
Пример #27
0
 /**
  * @param profile to start from
  * @param types to filter
  * @return list of concepts
  */
 public ArrayList<Concept> getConceptsForProfile(final Profile person, final List<Type> types) {
   final Node node = template.getNode(person.getNodeId());
   ArrayList<Concept> concepts = new ArrayList<Concept>();
   TraversalDescription td =
       Traversal.description()
           .depthFirst()
           .relationships(RelationshipTypes.LIKES, Direction.OUTGOING)
           .relationships(RelationshipTypes.FRIEND, Direction.OUTGOING)
           .relationships(RelationshipTypes.BORN_IN, Direction.OUTGOING)
           .relationships(RelationshipTypes.LIVES_IN, Direction.OUTGOING)
           .relationships(RelationshipTypes.EDUCATED_AT, Direction.OUTGOING)
           .relationships(RelationshipTypes.WORKS_AT, Direction.OUTGOING)
           .relationships(RelationshipTypes.BASED_IN, Direction.OUTGOING)
           .evaluator(
               new Evaluator() {
                 @Override
                 public Evaluation evaluate(Path path) {
                   if (path.lastRelationship() != null) {
                     if (path.lastRelationship().getType().equals(RelationshipTypes.FRIEND)) {
                       if (!path.lastRelationship().getStartNode().equals(node)) {
                         return Evaluation.EXCLUDE_AND_PRUNE;
                       } else {
                         return Evaluation.EXCLUDE_AND_CONTINUE;
                       }
                     } else {
                       if (path.endNode().hasProperty(NamespaceConstants.TYPE)) {
                         String conceptType =
                             path.endNode().getProperty(NamespaceConstants.TYPE).toString();
                         //									if(things.isInTypes(types,conceptType) |
                         // (FType.getTypeForFBType(conceptType) != null &&
                         // things.findThing(FType.getTypeForFBType(conceptType).getUri()) !=
                         // null)){
                         //										return Evaluation.INCLUDE_AND_PRUNE;
                         //									} else {
                         //										return Evaluation.EXCLUDE_AND_PRUNE;
                         //									}
                         if (conceptType.startsWith("http")) {
                           if (things.isInTypes(types, conceptType)) {
                             return Evaluation.INCLUDE_AND_PRUNE;
                           } else {
                             return Evaluation.EXCLUDE_AND_PRUNE;
                           }
                         } else {
                           if (things.isInTypesFromFBTypes(types, conceptType)) {
                             return Evaluation.INCLUDE_AND_PRUNE;
                           } else {
                             return Evaluation.EXCLUDE_AND_PRUNE;
                           }
                         }
                       } else {
                         return Evaluation.EXCLUDE_AND_PRUNE;
                       }
                     }
                   } else return Evaluation.EXCLUDE_AND_CONTINUE;
                 }
               });
   Traverser t = td.traverse(node);
   for (Path path : t) {
     Concept c = getByNode(path.endNode());
     concepts.add(c);
   }
   return concepts;
 }
Пример #28
0
  @Override
  protected Continuation exec(AppCommandParser parser, Session session, Output out)
      throws ShellException, RemoteException {
    assertCurrentIsNode(session);

    Node node = this.getCurrent(session).asNode();
    boolean caseInsensitiveFilters = parser.options().containsKey("i");
    boolean looseFilters = parser.options().containsKey("l");
    boolean quiet = parser.options().containsKey("q");

    // Order
    TraversalDescription description = Traversal.description();
    String order = parser.options().get("o");
    if (order != null) {
      description = description.order(parseOrder(order));
    }

    // Relationship types / expander
    String relationshipTypes = parser.options().get("r");
    if (relationshipTypes != null) {
      Map<String, Object> types = parseFilter(relationshipTypes, out);
      description =
          description.expand(
              toExpander(getServer().getDb(), null, types, caseInsensitiveFilters, looseFilters));
    }

    // Uniqueness
    String uniqueness = parser.options().get("u");
    if (uniqueness != null) {
      description = description.uniqueness(parseUniqueness(uniqueness));
    }

    // Depth limit
    String depthLimit = parser.options().get("d");
    if (depthLimit != null) {
      description = description.evaluator(toDepth(parseInt(depthLimit)));
    }

    String filterString = parser.options().get("f");
    Map<String, Object> filterMap = filterString != null ? parseFilter(filterString, out) : null;
    String commandToRun = parser.options().get("c");
    Collection<String> commandsToRun = new ArrayList<String>();
    if (commandToRun != null) {
      commandsToRun.addAll(Arrays.asList(commandToRun.split(Pattern.quote("&&"))));
    }
    for (Path path : description.traverse(node)) {
      boolean hit = false;
      if (filterMap == null) {
        hit = true;
      } else {
        Node endNode = path.endNode();
        Map<String, Boolean> matchPerFilterKey = new HashMap<String, Boolean>();
        for (String key : endNode.getPropertyKeys()) {
          for (Map.Entry<String, Object> filterEntry : filterMap.entrySet()) {
            String filterKey = filterEntry.getKey();
            if (matchPerFilterKey.containsKey(filterKey)) {
              continue;
            }

            if (matches(
                newPattern(filterKey, caseInsensitiveFilters),
                key,
                caseInsensitiveFilters,
                looseFilters)) {
              Object value = endNode.getProperty(key);
              String filterPattern =
                  filterEntry.getValue() != null ? filterEntry.getValue().toString() : null;
              if (matches(
                  newPattern(filterPattern, caseInsensitiveFilters),
                  value.toString(),
                  caseInsensitiveFilters,
                  looseFilters)) {
                matchPerFilterKey.put(filterKey, true);
              }
            }
          }
        }

        if (matchPerFilterKey.size() == filterMap.size()) {
          hit = true;
        }
      }
      if (hit) {
        if (commandsToRun.isEmpty()) {
          printPath(path, quiet, session, out);
        } else {
          printAndInterpretTemplateLines(
              commandsToRun,
              false,
              true,
              NodeOrRelationship.wrap(path.endNode()),
              getServer(),
              session,
              out);
        }
      }
    }
    return Continuation.INPUT_COMPLETE;
  }
 public Iterable<Node> getFriends(String name) {
   ResourceIterable<Node> users = db.findNodesByLabelAndProperty(USER, "name", name);
   Node startNode = IteratorUtil.single(users);
   return traversalDescription.traverse(startNode).nodes();
 }
Пример #30
0
  public String getContacts(@Name("filter") String filter) {
    StringWriter resultWriter = new StringWriter();
    JsonFactory f = new JsonFactory();
    f.setCodec(om);
    JsonGenerator g;
    try {
      g = f.createGenerator(resultWriter);

      final Node target = DB.getIndex().get("id", "agents").getSingle();
      TraversalDescription td =
          Traversal.description()
              .relationships(RelTypes.GROUPMEMBER, Direction.OUTGOING)
              .relationships(RelTypes.SUBGROUP, Direction.OUTGOING)
              .uniqueness(Uniqueness.NODE_PATH)
              .evaluator(
                  new Evaluator() {
                    @Override
                    public Evaluation evaluate(Path path) {
                      if (path.endNode().hasProperty("name")
                          && path.lastRelationship().isType(RelTypes.GROUPMEMBER)) {
                        return Evaluation.INCLUDE_AND_PRUNE;
                      }
                      return Evaluation.EXCLUDE_AND_CONTINUE;
                    }
                  });

      Traverser results = td.traverse(target);

      Multimap<Long, Path> groupByNode = ArrayListMultimap.create();

      Iterator<Path> paths = results.iterator();
      while (paths.hasNext()) {
        Path path = paths.next();
        groupByNode.put(path.endNode().getId(), path);
      }
      g.writeStartArray();
      for (Long nodeId : groupByNode.keySet()) {
        List<Path> pathList = (List<Path>) groupByNode.get(nodeId);
        g.writeStartObject();
        Node node = pathList.get(0).endNode();
        g.writeStringField("name", (String) node.getProperty("name"));
        g.writeArrayFieldStart("groups");
        for (Path path : pathList) {
          g.writeStartObject();
          g.writeStringField(
              "name", (String) path.lastRelationship().getStartNode().getProperty("name"));
          g.writeArrayFieldStart("path");
          for (Node pathStep : path.nodes()) {
            if (!pathStep.equals(node) && pathStep.hasProperty("name"))
              g.writeString((String) pathStep.getProperty("name"));
          }
          g.writeEndArray();
          g.writeEndObject();
        }
        g.writeEndArray();
        g.writeEndObject();
      }
      g.writeEndArray();
      g.flush();
    } catch (IOException e) {
      e.printStackTrace();
    }
    resultWriter.flush();
    return resultWriter.toString();
  }