Your problem is that a node can't be visited more than once in a traversal, right? Have you looked at the new traversal framework in 1.1-SNAPSHOT? It solves that problem in that you can specify uniqueness for the traverser... you can instead say that each Relationship can't be visited more than once, but Nodes can. Your example:
Map<Node, Integer> result = new HashMap<Node, Integer>(); for ( Node currentNode : TraversalFactory.createTraversalDescription() .breadthFirst().uniqueness(Uniqueness.RELATIONSHIP_GLOBAL) .relationships(MyRelationships.SIMILAR) .relationships(MyRelationships.CATEGORY) .prune(TraversalFactory.pruneAfterDepth(2)).traverse(node) ) { if(currentNode.hasProperty("category")) { if(result.get(currentNode) == null) { result.put(currentNode, 1); } else { result.put(currentNode, result.get(currentNode) + 1); } } } 2010/7/8 Rick Bullotta <rick.bullo...@burningskysoftware.com> > A performance improvement might be achieved by minimizing object > creation/hash inserts using a "counter" wrapper. > > - Create a simple class "Counter" with a single public property "count" of > type int (not Integer) with an initial value of 1 > > - Tweak your code to something like: > > public Map<String, Counter> findCategoriesForWord(String word) { > final Node node = index.getSingleNode("word", word); > final Map<String, Counter> result = new HashMap<String, Counter>(); > if(node != null) { > Traverser traverserWords = > node.traverse(Traverser.Order.BREADTH_FIRST, > StopEvaluator.DEPTH_ONE, new ReturnableEvaluator() { > @Override > public boolean isReturnableNode(TraversalPosition > traversalPosition) { > final Node currentNode = > traversalPosition.currentNode(); > final Iterator<Relationship> > relationshipIterator = > currentNode.getRelationships(MyRelationships.CATEGORY).iterator(); > while(relationshipIterator.hasNext()) { > final Relationship relationship = > relationshipIterator.next(); > final String categoryName = (String) > relationship.getProperty("catId"); > > Counter counter = > result.get(categoryName); > > if(counter == null) { > result.put(categoryName, new Counter()); > } else { > ++counter.count; > } > } > return true; > } > }, MyRelationships.SIMILAR, Direction.BOTH); > traverserWords.getAllNodes(); > } > return result; > } > > > -----Original Message----- > From: user-boun...@lists.neo4j.org [mailto:user-boun...@lists.neo4j.org] > On > Behalf Of Java Programmer > Sent: Thursday, July 08, 2010 8:12 AM > To: Neo4j user discussions > Subject: Re: [Neo4j] Is it possible to count common nodes when traversing? > > Hi, > Thanks for your answer but it's not exactly what I was on my mind - > word can belong to several categories, and different words can share > same category e.g.: > > "word 1" : "category 1", "category 2", "category 3" > "word 2" : "category 2", "category 3" > "word 3" : "category 3" > > there is relation between "word 1" and "word 2" and between "word 2" > and "word 3" (SIMILAR). > As a result when querying for "word 1" with depth 1, I would like to get: > "category 1" -> 1 (result), "category 2" -> 2, "category 3" -> 2 (not > 3 because it's out of depth) > > So far I have changed previous method to use the relationship with > property of categoryId, but I don't know if there won't be > a performance issues (I iterate for all relationship of the found node > (every similar), and store the categories in Map). If you could look > at it and tell me if the way of thinking is good, I would be very > appreciate: > > public Map<String, Integer> findCategoriesForWord(String word) { > final Node node = index.getSingleNode("word", word); > final Map<String, Integer> result = new HashMap<String, Integer>(); > if(node != null) { > Traverser traverserWords = > node.traverse(Traverser.Order.BREADTH_FIRST, > StopEvaluator.DEPTH_ONE, new ReturnableEvaluator() { > @Override > public boolean isReturnableNode(TraversalPosition > traversalPosition) { > final Node currentNode = > traversalPosition.currentNode(); > final Iterator<Relationship> > relationshipIterator = > currentNode.getRelationships(MyRelationships.CATEGORY).iterator(); > while(relationshipIterator.hasNext()) { > final Relationship relationship = > relationshipIterator.next(); > final String categoryName = (String) > relationship.getProperty("catId"); > if(result.get(categoryName) == null) { > result.put(categoryName, 1); > } else { > result.put(categoryName, > result.get(categoryName) + 1); > } > } > return true; > } > }, MyRelationships.SIMILAR, Direction.BOTH); > traverserWords.getAllNodes(); > } > return result; > } > > > On Thu, Jul 8, 2010 at 1:23 PM, Craig Taverner <cr...@amanzi.com> wrote: > > Your description seems to indicate that each word only belongs to one > > category, and if you want the category count, you will always get 1. But > > your code indicates tat: > > > > - You are counting the categories for similar works also > > - You are searching to depth 2 for both similar and category > > relationships, which seems to indicate you will also test all words in > > categories found (which are ignored since you only test category nodes, > but > > does cost time). > > > > If you do only have one category per word, and your question is "count > all > > categories for this word and similar words" I suggest remove the category > > relationship from the traverser, change depth to depth 1, use > > ReturnableEvaluator.ALL and in a for loop over the traverser iteration, > just > > do: > > for(Node word: traverserWords){ > > Node category = > > word.getSingleRelationship(CATEGORY,OUTGOING).getEndNode(); > > ..add or increment hash.. > > } > > (perhaps you need to change the direction and call getStartNode() > depending > > on what you use for direction) > > > > Now you can also increase the depth for looking for less similar words, > > since the traverser only follows the SIMILAR type). Also, if you have > more > > than one category per word, don't use getSingleRelationship, but loop > over > > getRelationships(). If you move to a category tree (nested categories), > then > > create a new traverser inside the loop of the outer one. > > > > On Thu, Jul 8, 2010 at 12:47 PM, Java Programmer > <jprogrami...@gmail.com>wrote: > > > >> Hello, > >> > >> I have two nodes [Word] and [Category], each [Word] can have a > >> [Category], and different [Word] can share same [Category]. > >> [Word] to another [Word] has relationship SIMILAR, [Word] to > >> [Category] has relationship Category. > >> I need to count how many Words is in Category, up to given depth. > >> When I use my traverser code, it traverse well but skips the > >> Categories already found in earlier iterations. > >> Here is the sample which don't work as it should for my requirements > >> (category counter always is 1, logging tells me that category is > >> visited only once, even if it is connected to word in one node away > >> neighbourhood), any ideas what can be improved? > >> > >> public Map<Node, Integer> findCategoriesForWord(String word) { > >> final Node node = index.getSingleNode("word", word); > >> final Map<Node, Integer> result = new HashMap<Node, Integer>(); > >> if(node != null) { > >> Traverser traverserWords = > >> node.traverse(Traverser.Order.BREADTH_FIRST, > >> new StopEvaluator() { > >> @Override > >> public boolean isStopNode(TraversalPosition > >> traversalPosition) { > >> return traversalPosition.depth() == 2; > >> } > >> }, new ReturnableEvaluator() { > >> @Override > >> public boolean isReturnableNode(TraversalPosition > >> traversalPosition) { > >> Node currentNode = > traversalPosition.currentNode(); > >> boolean returnable = > >> traversalPosition.currentNode().hasProperty("category"); > >> if(returnable) { > >> if(result.get(currentNode) == null) { > >> result.put(currentNode, 1); > >> } else { > >> result.put(currentNode, > >> result.get(currentNode) + 1); > >> } > >> } > >> return returnable; > >> } > >> }, MyRelationships.SIMILAR, Direction.BOTH, > >> MyRelationships.CATEGORY, Direction.BOTH); > >> traverserWords.getAllNodes(); > >> } > >> return result; > >> } > >> > >> > >> -- > >> Best regards, > >> Adrian > >> > >> http://www.codeappeal.com/ > >> _______________________________________________ > >> Neo4j mailing list > >> User@lists.neo4j.org > >> https://lists.neo4j.org/mailman/listinfo/user > >> > > _______________________________________________ > > Neo4j mailing list > > User@lists.neo4j.org > > https://lists.neo4j.org/mailman/listinfo/user > > > > > > -- > Best regards, > Adrian > > http://www.codeappeal.com/ > _______________________________________________ > Neo4j mailing list > User@lists.neo4j.org > https://lists.neo4j.org/mailman/listinfo/user > > _______________________________________________ > Neo4j mailing list > User@lists.neo4j.org > https://lists.neo4j.org/mailman/listinfo/user > -- Mattias Persson, [matt...@neotechnology.com] Hacker, Neo Technology www.neotechnology.com _______________________________________________ Neo4j mailing list User@lists.neo4j.org https://lists.neo4j.org/mailman/listinfo/user