Re: [Neo4j] New tentative API in trunk: Expander/Expansion
I agree, lets keep it immutable, then its safe to keep the expander around. Two suggestions: Your could provide a reusable expander: Expander e = Expanders.outgoing().along(FRIEND).and(ENEMY); for(Node n:e.expand(node)){ ... } or a onetime expander: for(Node n : node.expand().outgoing().along(FRIEND).and(ENEMY)){ ... } OR for(Node n : node.expand().outgoing().include(FRIEND).include(ENEMY)){ ... } OR for(Node n : node.expand().outgoing().with(FRIEND).with(ENEMY)){ ... } -atle ___ Neo4j mailing list User@lists.neo4j.org https://lists.neo4j.org/mailman/listinfo/user
Re: [Neo4j] New tentative API in trunk: Expander/Expansion
I guess I would have just added a clear() method to the expansion. But of course I understand that using mutable expansions requires that the user actually understand the implications, which goes against the simplicity of the DSL. On Thu, Jun 24, 2010 at 12:23 AM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: The problem with the code below is that once you've used the Person.getFriends(minAge)-method once, the friends-expansion will have that filter added to it forever (if it's mutable), and that means that you will never be able to get the younger friends of that person. However, reusing an expansion might be so uncommon that it's not even worth bothering with. But if so, it will almost always be used fluent-style, and the use case for being able to mutate it disappears. Ergo, let's keep it immutable, since it enables more use cases. -t On Wed, Jun 23, 2010 at 8:47 PM, Craig Taverner cr...@amanzi.com wrote: Mutable objects have their issues, and yet this is a common and popular paradigm in DSL design. I guess however the point with a DSL is that it is so simple and limited that it compensates for the potential risks. Similar to the dynamic versus static language argument. Now there are ways to reduce the risk. If I remember correctly, one pattern commonly used in the DSL book was to remain strict with model objects, but slack on model builder objects. In this case the Node and Person objects are model objects, and we would put the fancy DSL stuff into a separate class, not as a static method of the Person class. This can help conceptually separate the solid and reliable model from the convenient DSL. On a separate note, perhaps I'm just being slow, but I don't see the aspects of the code below that would be disabled by a mutable builder? Is it the final on 'friends'? That keyword should not stop modifying the contents of friends. ANd you code below does not expose the friends instance to outside influences, so no-one can modify it anyway. What am I missing. On Wed, Jun 23, 2010 at 8:15 PM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: Because mutable objects are evil. It would for example make it impossible to write classes like this: class Person { private final ExpansionNode friends; Person(Node node) { this.friends = node.expand( FRIEND ).nodes(); } IterablePerson getFriends() { return persons( friends ); } IterablePerson getFriends( final int minimumAge ) { return persons( friends.filterNodes( new PredicateNode() { public boolean accept(Node friend) { return minimumAge = (Integer)friend.getProperty(age); } }) ); } static IterablePerson persons( IterableNode persons ) { return IterableWrapperPerson, Node( persons ) { protected Person underlyingObjectToObject( Node person ) { return new Person( person ); } } } } This might be an acceptable loss though. This could be a case where it is ok to reuse the same object and mutate the internal state. It's something to think about... -tobias On Wed, Jun 23, 2010 at 7:10 PM, Craig Taverner cr...@amanzi.com wrote: Why not have includes() return the same instance with internal state changed, then the various call options are equivalent. On Jun 23, 2010 6:41 PM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: On Wed, Jun 23, 2010 at 6:10 PM, Craig Taverner cr...@amanzi.com wrote: (I also noticed that r... I get that feeling as well. Another feeling I get with includes() is that it might be possible to do the following: ExpansionRelationship expansion = startNode.expand( KNOWS ); expansion.includes( LIKES ); expansion.includes( LOVES ); for (Node node : expansion.nodes()) { ... } With includes() one gets the feeling that the above would expand LOVES, LIKES and KNOWS relationships, but it will in fact only expand KNOWS relationships. With and() I don't think that mistake would be as common. Cheers, -- Tobias Ivarsson tobias.ivars...@neotechnology.com Hacker, Neo Technology www.neotechnology.com Cel... ___ Neo4j mailing list User@lists.neo4j.org https://lists.neo4j.org/mailman/listinfo/user -- Tobias Ivarsson tobias.ivars...@neotechnology.com Hacker, Neo Technology www.neotechnology.com Cellphone: +46 706 534857 ___ Neo4j mailing list User@lists.neo4j.org https://lists.neo4j.org/mailman/listinfo/user ___ Neo4j mailing list User@lists.neo4j.org
Re: [Neo4j] New tentative API in trunk: Expander/Expansion
Hi Tobias, It seems as though the new changes have broken the AStar code I'm using. I use: neo4j-apoc 1.1-SNAPSHOT neo4j-graph-algo 0.5-SNAPSHOT AStar uses DefaultExpander and can no longer find it. Here's an example of the code that worked until now. DefaultExpander relExpander = new DefaultExpander(); relExpander.add(GISRelationshipTypes.BICYCLE_WAY, Direction.BOTH); AStar sp = new AStar(graphDb, relExpander, costEval, estimateEval); Path path = sp.findSinglePath(startNode, endNode); The problem seems to be that AStar wants a RelationshipExpander but now I can only create an ExpansionRelationship. Do you have any suggestions as to how to make this work again? Regards, Alex On Wed, Jun 23, 2010 at 11:14 AM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: Hi Neo4j enthusiasts! Yesterday I committed an API that Mattias and I have been working on for a few days. It comes in the form of two new interfaces Expander and Expansion (in the org.neo4j.graphdb package), and four new methods in the Node interface (method names starting with expand). The two main problems this API solves are: 1. Adds a clean way for getting related nodes from a source node. 2. Adds a type safe way for declaratively specifying any combination of RelationshipTypes and Directions to expand. This replaces what was actually an anti-pattern, but something we saw people doing a lot: using a depth-one traversal to get the nodes related to a node, without needing to bother with the Relationship interface. Example: // The most convenient way to write it in the past: Node source = ... Traverser traverser = source.traverse( Traverser.Order.DEPTH_FIRST, new StopAtDepth( 1 ), ReturnableEvaluator.ALL_BUT_START_NODE, TYPE_ONE, Direction.INCOMING, TYPE_TWO, Direction.OUTGOING); for (Node related : traverser) { doSomethingWith( related ); } // The previously recommended (and bloated) way of doing it: Node source = ... for (Relationship rel : source.getRelationships( TYPE_ONE, TYPE_TWO )) { Node related; if (rel.isType(TYPE_ONE)) { related = rel.getStartNode(); if (related.equals(source)) continue; // we only want INCOMING TYPE_ONE } else if (rel.isType(TYPE_TWO)) { related = rel.getEndNode(); if (related.equals(source)) continue; // we only want OUTGOING TYPE_TWO } else { continue; // should never happen, but makes javac know that related is != null } doSomethingWith( related ); } // With the new API: Node source = ... for (Node related : source.expand( TYPE_ONE, Direction.INCOMING ) .add( TYPE_TWO, Direction.OUTGOING ).nodes()) { doSomethingWith( related ); } The return type of the Node.expand(...)-methods are the new Expansion type, it defaults to expanding to Relationship, but the Expansion.nodes()-method makes it expand to Node. It also contains the add()-methods seen above for specifying RelationshipTypes to include in the expansion. The spelling of this method isn't perfectly decided yet, we are choosing between add, and and include, we want something that reads nicely in the code, but doesn't conflict with keywords in other JVM-languages (and is a keyword in Python, and I think include means something special in Ruby). There is also an Expansion.exlude(RelationshipType)-method for use together with the Node.expandAll(). The Expansion is backed by the newly added companion interface Expander. This is an extension of RelationshipExpander that adds builder capabilities. It turns the functionality of the DefultExpander implementation class (now removed) into an interface in the API. RelationshipExpander is still around as a single method interface, which is useful for when you want to implement your own expansion logic. This API is added to trunk so that we can get feedback from everyone who use the snapshot builds of Neo4j, if the response to this API isn't positive, it will probably be removed before the release of 1.1, so please submit comments in this thread on what you think about this API. Happy Hacking, -- Tobias Ivarsson tobias.ivars...@neotechnology.com Hacker, Neo Technology www.neotechnology.com Cellphone: +46 706 534857 ___ 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
Re: [Neo4j] New tentative API in trunk: Expander/Expansion
Hi! See: http://www.mail-archive.com/user@lists.neo4j.org/msg04044.html /anders On 06/23/2010 03:44 PM, Alex Averbuch wrote: Hi Tobias, It seems as though the new changes have broken the AStar code I'm using. I use: neo4j-apoc 1.1-SNAPSHOT neo4j-graph-algo 0.5-SNAPSHOT AStar uses DefaultExpander and can no longer find it. Here's an example of the code that worked until now. DefaultExpander relExpander = new DefaultExpander(); relExpander.add(GISRelationshipTypes.BICYCLE_WAY, Direction.BOTH); AStar sp = new AStar(graphDb, relExpander, costEval, estimateEval); Path path = sp.findSinglePath(startNode, endNode); The problem seems to be that AStar wants a RelationshipExpander but now I can only create an ExpansionRelationship. Do you have any suggestions as to how to make this work again? Regards, Alex On Wed, Jun 23, 2010 at 11:14 AM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: Hi Neo4j enthusiasts! Yesterday I committed an API that Mattias and I have been working on for a few days. It comes in the form of two new interfaces Expander and Expansion (in the org.neo4j.graphdb package), and four new methods in the Node interface (method names starting with expand). The two main problems this API solves are: 1. Adds a clean way for getting related nodes from a source node. 2. Adds a type safe way for declaratively specifying any combination of RelationshipTypes and Directions to expand. This replaces what was actually an anti-pattern, but something we saw people doing a lot: using a depth-one traversal to get the nodes related to a node, without needing to bother with the Relationship interface. Example: // The most convenient way to write it in the past: Node source = ... Traverser traverser = source.traverse( Traverser.Order.DEPTH_FIRST, new StopAtDepth( 1 ), ReturnableEvaluator.ALL_BUT_START_NODE, TYPE_ONE, Direction.INCOMING, TYPE_TWO, Direction.OUTGOING); for (Node related : traverser) { doSomethingWith( related ); } // The previously recommended (and bloated) way of doing it: Node source = ... for (Relationship rel : source.getRelationships( TYPE_ONE, TYPE_TWO )) { Node related; if (rel.isType(TYPE_ONE)) { related = rel.getStartNode(); if (related.equals(source)) continue; // we only want INCOMING TYPE_ONE } else if (rel.isType(TYPE_TWO)) { related = rel.getEndNode(); if (related.equals(source)) continue; // we only want OUTGOING TYPE_TWO } else { continue; // should never happen, but makes javac know that related is != null } doSomethingWith( related ); } // With the new API: Node source = ... for (Node related : source.expand( TYPE_ONE, Direction.INCOMING ) .add( TYPE_TWO, Direction.OUTGOING ).nodes()) { doSomethingWith( related ); } The return type of the Node.expand(...)-methods are the new Expansion type, it defaults to expanding to Relationship, but the Expansion.nodes()-method makes it expand to Node. It also contains the add()-methods seen above for specifying RelationshipTypes to include in the expansion. The spelling of this method isn't perfectly decided yet, we are choosing between add, and and include, we want something that reads nicely in the code, but doesn't conflict with keywords in other JVM-languages (and is a keyword in Python, and I think include means something special in Ruby). There is also an Expansion.exlude(RelationshipType)-method for use together with the Node.expandAll(). The Expansion is backed by the newly added companion interface Expander. This is an extension of RelationshipExpander that adds builder capabilities. It turns the functionality of the DefultExpander implementation class (now removed) into an interface in the API. RelationshipExpander is still around as a single method interface, which is useful for when you want to implement your own expansion logic. This API is added to trunk so that we can get feedback from everyone who use the snapshot builds of Neo4j, if the response to this API isn't positive, it will probably be removed before the release of 1.1, so please submit comments in this thread on what you think about this API. Happy Hacking, -- Tobias Ivarssontobias.ivars...@neotechnology.com Hacker, Neo Technology www.neotechnology.com Cellphone: +46 706 534857 ___ 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 ___ Neo4j mailing list User@lists.neo4j.org https://lists.neo4j.org/mailman/listinfo/user
Re: [Neo4j] New tentative API in trunk: Expander/Expansion
Also, the latest graph-algo is 0.6-SNAPSHOT... so use that instead 2010/6/23 Anders Nawroth and...@neotechnology.com Hi! See: http://www.mail-archive.com/user@lists.neo4j.org/msg04044.html /anders On 06/23/2010 03:44 PM, Alex Averbuch wrote: Hi Tobias, It seems as though the new changes have broken the AStar code I'm using. I use: neo4j-apoc 1.1-SNAPSHOT neo4j-graph-algo 0.5-SNAPSHOT AStar uses DefaultExpander and can no longer find it. Here's an example of the code that worked until now. DefaultExpander relExpander = new DefaultExpander(); relExpander.add(GISRelationshipTypes.BICYCLE_WAY, Direction.BOTH); AStar sp = new AStar(graphDb, relExpander, costEval, estimateEval); Path path = sp.findSinglePath(startNode, endNode); The problem seems to be that AStar wants a RelationshipExpander but now I can only create an ExpansionRelationship. Do you have any suggestions as to how to make this work again? Regards, Alex On Wed, Jun 23, 2010 at 11:14 AM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: Hi Neo4j enthusiasts! Yesterday I committed an API that Mattias and I have been working on for a few days. It comes in the form of two new interfaces Expander and Expansion (in the org.neo4j.graphdb package), and four new methods in the Node interface (method names starting with expand). The two main problems this API solves are: 1. Adds a clean way for getting related nodes from a source node. 2. Adds a type safe way for declaratively specifying any combination of RelationshipTypes and Directions to expand. This replaces what was actually an anti-pattern, but something we saw people doing a lot: using a depth-one traversal to get the nodes related to a node, without needing to bother with the Relationship interface. Example: // The most convenient way to write it in the past: Node source = ... Traverser traverser = source.traverse( Traverser.Order.DEPTH_FIRST, new StopAtDepth( 1 ), ReturnableEvaluator.ALL_BUT_START_NODE, TYPE_ONE, Direction.INCOMING, TYPE_TWO, Direction.OUTGOING); for (Node related : traverser) { doSomethingWith( related ); } // The previously recommended (and bloated) way of doing it: Node source = ... for (Relationship rel : source.getRelationships( TYPE_ONE, TYPE_TWO )) { Node related; if (rel.isType(TYPE_ONE)) { related = rel.getStartNode(); if (related.equals(source)) continue; // we only want INCOMING TYPE_ONE } else if (rel.isType(TYPE_TWO)) { related = rel.getEndNode(); if (related.equals(source)) continue; // we only want OUTGOING TYPE_TWO } else { continue; // should never happen, but makes javac know that related is != null } doSomethingWith( related ); } // With the new API: Node source = ... for (Node related : source.expand( TYPE_ONE, Direction.INCOMING ) .add( TYPE_TWO, Direction.OUTGOING ).nodes()) { doSomethingWith( related ); } The return type of the Node.expand(...)-methods are the new Expansion type, it defaults to expanding to Relationship, but the Expansion.nodes()-method makes it expand to Node. It also contains the add()-methods seen above for specifying RelationshipTypes to include in the expansion. The spelling of this method isn't perfectly decided yet, we are choosing between add, and and include, we want something that reads nicely in the code, but doesn't conflict with keywords in other JVM-languages (and is a keyword in Python, and I think include means something special in Ruby). There is also an Expansion.exlude(RelationshipType)-method for use together with the Node.expandAll(). The Expansion is backed by the newly added companion interface Expander. This is an extension of RelationshipExpander that adds builder capabilities. It turns the functionality of the DefultExpander implementation class (now removed) into an interface in the API. RelationshipExpander is still around as a single method interface, which is useful for when you want to implement your own expansion logic. This API is added to trunk so that we can get feedback from everyone who use the snapshot builds of Neo4j, if the response to this API isn't positive, it will probably be removed before the release of 1.1, so please submit comments in this thread on what you think about this API. Happy Hacking, -- Tobias Ivarssontobias.ivars...@neotechnology.com Hacker, Neo Technology www.neotechnology.com Cellphone: +46 706 534857 ___ 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
Re: [Neo4j] New tentative API in trunk: Expander/Expansion
Hi guys, thanks! I've pulled the latest java-astar-routing and looking at it now. Have changed to SNAPSHOT 0.6 too. Has the AStar algorithm been changed to use the Traversal framework now? If so, is there any way I can use the old AStar version? The last one required neo4j-apoc 1.1-SNAPSHOT neo4j-graph-algo 0.5-SNAPSHOT, but no longer works with these. Is there any combination of neo4j-graph-algo and neo4j-apoc that will work with the old version of AStar? My problem is this... We are in the final stages of evaluation for our thesis and have been asked if we can run a bunch of extra experiments. We use AStar on the GIS dataset experiments. We do NOT want to use the Traversal framework at all as the way we log traffic is by listening to the Add, Remove, Delete, Get, etc methods of GraphDatabaseService. The Traversal framework goes around these as far as I know, so we would lose our ability to monitor. Any suggestions would be great! Thanks, Alex On Wed, Jun 23, 2010 at 3:52 PM, Mattias Persson matt...@neotechnology.comwrote: Also, the latest graph-algo is 0.6-SNAPSHOT... so use that instead 2010/6/23 Anders Nawroth and...@neotechnology.com Hi! See: http://www.mail-archive.com/user@lists.neo4j.org/msg04044.html /anders On 06/23/2010 03:44 PM, Alex Averbuch wrote: Hi Tobias, It seems as though the new changes have broken the AStar code I'm using. I use: neo4j-apoc 1.1-SNAPSHOT neo4j-graph-algo 0.5-SNAPSHOT AStar uses DefaultExpander and can no longer find it. Here's an example of the code that worked until now. DefaultExpander relExpander = new DefaultExpander(); relExpander.add(GISRelationshipTypes.BICYCLE_WAY, Direction.BOTH); AStar sp = new AStar(graphDb, relExpander, costEval, estimateEval); Path path = sp.findSinglePath(startNode, endNode); The problem seems to be that AStar wants a RelationshipExpander but now I can only create an ExpansionRelationship. Do you have any suggestions as to how to make this work again? Regards, Alex On Wed, Jun 23, 2010 at 11:14 AM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: Hi Neo4j enthusiasts! Yesterday I committed an API that Mattias and I have been working on for a few days. It comes in the form of two new interfaces Expander and Expansion (in the org.neo4j.graphdb package), and four new methods in the Node interface (method names starting with expand). The two main problems this API solves are: 1. Adds a clean way for getting related nodes from a source node. 2. Adds a type safe way for declaratively specifying any combination of RelationshipTypes and Directions to expand. This replaces what was actually an anti-pattern, but something we saw people doing a lot: using a depth-one traversal to get the nodes related to a node, without needing to bother with the Relationship interface. Example: // The most convenient way to write it in the past: Node source = ... Traverser traverser = source.traverse( Traverser.Order.DEPTH_FIRST, new StopAtDepth( 1 ), ReturnableEvaluator.ALL_BUT_START_NODE, TYPE_ONE, Direction.INCOMING, TYPE_TWO, Direction.OUTGOING); for (Node related : traverser) { doSomethingWith( related ); } // The previously recommended (and bloated) way of doing it: Node source = ... for (Relationship rel : source.getRelationships( TYPE_ONE, TYPE_TWO )) { Node related; if (rel.isType(TYPE_ONE)) { related = rel.getStartNode(); if (related.equals(source)) continue; // we only want INCOMING TYPE_ONE } else if (rel.isType(TYPE_TWO)) { related = rel.getEndNode(); if (related.equals(source)) continue; // we only want OUTGOING TYPE_TWO } else { continue; // should never happen, but makes javac know that related is != null } doSomethingWith( related ); } // With the new API: Node source = ... for (Node related : source.expand( TYPE_ONE, Direction.INCOMING ) .add( TYPE_TWO, Direction.OUTGOING ).nodes()) { doSomethingWith( related ); } The return type of the Node.expand(...)-methods are the new Expansion type, it defaults to expanding to Relationship, but the Expansion.nodes()-method makes it expand to Node. It also contains the add()-methods seen above for specifying RelationshipTypes to include in the expansion. The spelling of this method isn't perfectly decided yet, we are choosing between add, and and include, we want something that reads nicely in the code, but doesn't conflict with keywords in other JVM-languages (and is a keyword in Python, and I think include means something special in Ruby). There is also an Expansion.exlude(RelationshipType)-method for use together with the Node.expandAll().
Re: [Neo4j] New tentative API in trunk: Expander/Expansion
It works with graph-algo 0.6-SNAPSHOT and there's an AStar.java (which is the old version) and one ExperimentalAStar.java which uses the new traversal framework. 2010/6/23 Alex Averbuch alex.averb...@gmail.com Hi guys, thanks! I've pulled the latest java-astar-routing and looking at it now. Have changed to SNAPSHOT 0.6 too. Has the AStar algorithm been changed to use the Traversal framework now? If so, is there any way I can use the old AStar version? The last one required neo4j-apoc 1.1-SNAPSHOT neo4j-graph-algo 0.5-SNAPSHOT, but no longer works with these. Is there any combination of neo4j-graph-algo and neo4j-apoc that will work with the old version of AStar? My problem is this... We are in the final stages of evaluation for our thesis and have been asked if we can run a bunch of extra experiments. We use AStar on the GIS dataset experiments. We do NOT want to use the Traversal framework at all as the way we log traffic is by listening to the Add, Remove, Delete, Get, etc methods of GraphDatabaseService. The Traversal framework goes around these as far as I know, so we would lose our ability to monitor. Any suggestions would be great! Thanks, Alex On Wed, Jun 23, 2010 at 3:52 PM, Mattias Persson matt...@neotechnology.comwrote: Also, the latest graph-algo is 0.6-SNAPSHOT... so use that instead 2010/6/23 Anders Nawroth and...@neotechnology.com Hi! See: http://www.mail-archive.com/user@lists.neo4j.org/msg04044.html /anders On 06/23/2010 03:44 PM, Alex Averbuch wrote: Hi Tobias, It seems as though the new changes have broken the AStar code I'm using. I use: neo4j-apoc 1.1-SNAPSHOT neo4j-graph-algo 0.5-SNAPSHOT AStar uses DefaultExpander and can no longer find it. Here's an example of the code that worked until now. DefaultExpander relExpander = new DefaultExpander(); relExpander.add(GISRelationshipTypes.BICYCLE_WAY, Direction.BOTH); AStar sp = new AStar(graphDb, relExpander, costEval, estimateEval); Path path = sp.findSinglePath(startNode, endNode); The problem seems to be that AStar wants a RelationshipExpander but now I can only create an ExpansionRelationship. Do you have any suggestions as to how to make this work again? Regards, Alex On Wed, Jun 23, 2010 at 11:14 AM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: Hi Neo4j enthusiasts! Yesterday I committed an API that Mattias and I have been working on for a few days. It comes in the form of two new interfaces Expander and Expansion (in the org.neo4j.graphdb package), and four new methods in the Node interface (method names starting with expand). The two main problems this API solves are: 1. Adds a clean way for getting related nodes from a source node. 2. Adds a type safe way for declaratively specifying any combination of RelationshipTypes and Directions to expand. This replaces what was actually an anti-pattern, but something we saw people doing a lot: using a depth-one traversal to get the nodes related to a node, without needing to bother with the Relationship interface. Example: // The most convenient way to write it in the past: Node source = ... Traverser traverser = source.traverse( Traverser.Order.DEPTH_FIRST, new StopAtDepth( 1 ), ReturnableEvaluator.ALL_BUT_START_NODE, TYPE_ONE, Direction.INCOMING, TYPE_TWO, Direction.OUTGOING); for (Node related : traverser) { doSomethingWith( related ); } // The previously recommended (and bloated) way of doing it: Node source = ... for (Relationship rel : source.getRelationships( TYPE_ONE, TYPE_TWO )) { Node related; if (rel.isType(TYPE_ONE)) { related = rel.getStartNode(); if (related.equals(source)) continue; // we only want INCOMING TYPE_ONE } else if (rel.isType(TYPE_TWO)) { related = rel.getEndNode(); if (related.equals(source)) continue; // we only want OUTGOING TYPE_TWO } else { continue; // should never happen, but makes javac know that related is != null } doSomethingWith( related ); } // With the new API: Node source = ... for (Node related : source.expand( TYPE_ONE, Direction.INCOMING ) .add( TYPE_TWO, Direction.OUTGOING ).nodes()) { doSomethingWith( related ); } The return type of the Node.expand(...)-methods are the new Expansion type, it defaults to expanding to Relationship, but the Expansion.nodes()-method makes it expand to Node. It also contains the add()-methods seen above for specifying RelationshipTypes to include in the expansion. The spelling of this method isn't perfectly decided yet, we are
Re: [Neo4j] New tentative API in trunk: Expander/Expansion
Sweet, Experiments are running fine again. Thanks for the quick help! Alex On Wed, Jun 23, 2010 at 4:17 PM, Mattias Persson matt...@neotechnology.comwrote: It works with graph-algo 0.6-SNAPSHOT and there's an AStar.java (which is the old version) and one ExperimentalAStar.java which uses the new traversal framework. 2010/6/23 Alex Averbuch alex.averb...@gmail.com Hi guys, thanks! I've pulled the latest java-astar-routing and looking at it now. Have changed to SNAPSHOT 0.6 too. Has the AStar algorithm been changed to use the Traversal framework now? If so, is there any way I can use the old AStar version? The last one required neo4j-apoc 1.1-SNAPSHOT neo4j-graph-algo 0.5-SNAPSHOT, but no longer works with these. Is there any combination of neo4j-graph-algo and neo4j-apoc that will work with the old version of AStar? My problem is this... We are in the final stages of evaluation for our thesis and have been asked if we can run a bunch of extra experiments. We use AStar on the GIS dataset experiments. We do NOT want to use the Traversal framework at all as the way we log traffic is by listening to the Add, Remove, Delete, Get, etc methods of GraphDatabaseService. The Traversal framework goes around these as far as I know, so we would lose our ability to monitor. Any suggestions would be great! Thanks, Alex On Wed, Jun 23, 2010 at 3:52 PM, Mattias Persson matt...@neotechnology.comwrote: Also, the latest graph-algo is 0.6-SNAPSHOT... so use that instead 2010/6/23 Anders Nawroth and...@neotechnology.com Hi! See: http://www.mail-archive.com/user@lists.neo4j.org/msg04044.html /anders On 06/23/2010 03:44 PM, Alex Averbuch wrote: Hi Tobias, It seems as though the new changes have broken the AStar code I'm using. I use: neo4j-apoc 1.1-SNAPSHOT neo4j-graph-algo 0.5-SNAPSHOT AStar uses DefaultExpander and can no longer find it. Here's an example of the code that worked until now. DefaultExpander relExpander = new DefaultExpander(); relExpander.add(GISRelationshipTypes.BICYCLE_WAY, Direction.BOTH); AStar sp = new AStar(graphDb, relExpander, costEval, estimateEval); Path path = sp.findSinglePath(startNode, endNode); The problem seems to be that AStar wants a RelationshipExpander but now I can only create an ExpansionRelationship. Do you have any suggestions as to how to make this work again? Regards, Alex On Wed, Jun 23, 2010 at 11:14 AM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: Hi Neo4j enthusiasts! Yesterday I committed an API that Mattias and I have been working on for a few days. It comes in the form of two new interfaces Expander and Expansion (in the org.neo4j.graphdb package), and four new methods in the Node interface (method names starting with expand). The two main problems this API solves are: 1. Adds a clean way for getting related nodes from a source node. 2. Adds a type safe way for declaratively specifying any combination of RelationshipTypes and Directions to expand. This replaces what was actually an anti-pattern, but something we saw people doing a lot: using a depth-one traversal to get the nodes related to a node, without needing to bother with the Relationship interface. Example: // The most convenient way to write it in the past: Node source = ... Traverser traverser = source.traverse( Traverser.Order.DEPTH_FIRST, new StopAtDepth( 1 ), ReturnableEvaluator.ALL_BUT_START_NODE, TYPE_ONE, Direction.INCOMING, TYPE_TWO, Direction.OUTGOING); for (Node related : traverser) { doSomethingWith( related ); } // The previously recommended (and bloated) way of doing it: Node source = ... for (Relationship rel : source.getRelationships( TYPE_ONE, TYPE_TWO )) { Node related; if (rel.isType(TYPE_ONE)) { related = rel.getStartNode(); if (related.equals(source)) continue; // we only want INCOMING TYPE_ONE } else if (rel.isType(TYPE_TWO)) { related = rel.getEndNode(); if (related.equals(source)) continue; // we only want OUTGOING TYPE_TWO } else { continue; // should never happen, but makes javac know that related is != null } doSomethingWith( related ); } // With the new API: Node source = ... for (Node related : source.expand( TYPE_ONE, Direction.INCOMING ) .add( TYPE_TWO, Direction.OUTGOING ).nodes()) { doSomethingWith( related ); } The return type of the Node.expand(...)-methods are the new
Re: [Neo4j] New tentative API in trunk: Expander/Expansion
Did anyone have an opinion on what to call the methods on the Expansion interface that specify which types to expand. Alternative 1) ExpansionT and( RelationshipType type ); ExpansionT and( RelationshipType type, Direction direction ); ExpansionT not( RelationshipType type ); Examples: for (Node node : startNode.expand( KNOWS ) .and( LIKES ) .and( LOVES ) ) { doSomethingWith(node); } ExpansionRelationship expansion = startNode.expand( KNOWS ); expansion = expansion.and( LIKES ); expansion = expansion.and( LOVES ); Alternative 2) ExpansionT including( RelationshipType type ); ExpansionT including( RelationshipType type, Direction direction ); ExpansionT excluding( RelationshipType type ); Examples: for (Node node : startNode.expand( KNOWS ) .including( LIKES ) .including( LOVES ) ) { doSomethingWith(node); } ExpansionRelationship expansion = startNode.expand( KNOWS ); expansion = expansion.including( LIKES ); expansion = expansion.including( LOVES ); Cheers, Tobias On Wed, Jun 23, 2010 at 11:14 AM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: Hi Neo4j enthusiasts! Yesterday I committed an API that Mattias and I have been working on for a few days. It comes in the form of two new interfaces Expander and Expansion (in the org.neo4j.graphdb package), and four new methods in the Node interface (method names starting with expand). The two main problems this API solves are: 1. Adds a clean way for getting related nodes from a source node. 2. Adds a type safe way for declaratively specifying any combination of RelationshipTypes and Directions to expand. This replaces what was actually an anti-pattern, but something we saw people doing a lot: using a depth-one traversal to get the nodes related to a node, without needing to bother with the Relationship interface. Example: // The most convenient way to write it in the past: Node source = ... Traverser traverser = source.traverse( Traverser.Order.DEPTH_FIRST, new StopAtDepth( 1 ), ReturnableEvaluator.ALL_BUT_START_NODE, TYPE_ONE, Direction.INCOMING, TYPE_TWO, Direction.OUTGOING); for (Node related : traverser) { doSomethingWith( related ); } // The previously recommended (and bloated) way of doing it: Node source = ... for (Relationship rel : source.getRelationships( TYPE_ONE, TYPE_TWO )) { Node related; if (rel.isType(TYPE_ONE)) { related = rel.getStartNode(); if (related.equals(source)) continue; // we only want INCOMING TYPE_ONE } else if (rel.isType(TYPE_TWO)) { related = rel.getEndNode(); if (related.equals(source)) continue; // we only want OUTGOING TYPE_TWO } else { continue; // should never happen, but makes javac know that related is != null } doSomethingWith( related ); } // With the new API: Node source = ... for (Node related : source.expand( TYPE_ONE, Direction.INCOMING ) .add( TYPE_TWO, Direction.OUTGOING ).nodes()) { doSomethingWith( related ); } The return type of the Node.expand(...)-methods are the new Expansion type, it defaults to expanding to Relationship, but the Expansion.nodes()-method makes it expand to Node. It also contains the add()-methods seen above for specifying RelationshipTypes to include in the expansion. The spelling of this method isn't perfectly decided yet, we are choosing between add, and and include, we want something that reads nicely in the code, but doesn't conflict with keywords in other JVM-languages (and is a keyword in Python, and I think include means something special in Ruby). There is also an Expansion.exlude(RelationshipType)-method for use together with the Node.expandAll(). The Expansion is backed by the newly added companion interface Expander. This is an extension of RelationshipExpander that adds builder capabilities. It turns the functionality of the DefultExpander implementation class (now removed) into an interface in the API. RelationshipExpander is still around as a single method interface, which is useful for when you want to implement your own expansion logic. This API is added to trunk so that we can get feedback from everyone who use the snapshot builds of Neo4j, if the response to this API isn't positive, it will probably be removed before the release of 1.1, so please submit comments in this thread on what you think about this API. Happy Hacking, -- Tobias Ivarsson tobias.ivars...@neotechnology.com Hacker, Neo Technology www.neotechnology.com Cellphone: +46 706 534857 -- Tobias Ivarsson tobias.ivars...@neotechnology.com Hacker, Neo Technology www.neotechnology.com Cellphone: +46 706 534857 ___ Neo4j mailing list User@lists.neo4j.org https://lists.neo4j.org/mailman/listinfo/user
Re: [Neo4j] New tentative API in trunk: Expander/Expansion
Hi, Personally I'd prefer and/not. It's intuitive to any programmer and has the bonus of being much shorter, so long complex expansions will appear less messy in practice. On Wed, Jun 23, 2010 at 5:45 PM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: Did anyone have an opinion on what to call the methods on the Expansion interface that specify which types to expand. Alternative 1) ExpansionT and( RelationshipType type ); ExpansionT and( RelationshipType type, Direction direction ); ExpansionT not( RelationshipType type ); Examples: for (Node node : startNode.expand( KNOWS ) .and( LIKES ) .and( LOVES ) ) { doSomethingWith(node); } ExpansionRelationship expansion = startNode.expand( KNOWS ); expansion = expansion.and( LIKES ); expansion = expansion.and( LOVES ); Alternative 2) ExpansionT including( RelationshipType type ); ExpansionT including( RelationshipType type, Direction direction ); ExpansionT excluding( RelationshipType type ); Examples: for (Node node : startNode.expand( KNOWS ) .including( LIKES ) .including( LOVES ) ) { doSomethingWith(node); } ExpansionRelationship expansion = startNode.expand( KNOWS ); expansion = expansion.including( LIKES ); expansion = expansion.including( LOVES ); Cheers, Tobias On Wed, Jun 23, 2010 at 11:14 AM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: Hi Neo4j enthusiasts! Yesterday I committed an API that Mattias and I have been working on for a few days. It comes in the form of two new interfaces Expander and Expansion (in the org.neo4j.graphdb package), and four new methods in the Node interface (method names starting with expand). The two main problems this API solves are: 1. Adds a clean way for getting related nodes from a source node. 2. Adds a type safe way for declaratively specifying any combination of RelationshipTypes and Directions to expand. This replaces what was actually an anti-pattern, but something we saw people doing a lot: using a depth-one traversal to get the nodes related to a node, without needing to bother with the Relationship interface. Example: // The most convenient way to write it in the past: Node source = ... Traverser traverser = source.traverse( Traverser.Order.DEPTH_FIRST, new StopAtDepth( 1 ), ReturnableEvaluator.ALL_BUT_START_NODE, TYPE_ONE, Direction.INCOMING, TYPE_TWO, Direction.OUTGOING); for (Node related : traverser) { doSomethingWith( related ); } // The previously recommended (and bloated) way of doing it: Node source = ... for (Relationship rel : source.getRelationships( TYPE_ONE, TYPE_TWO )) { Node related; if (rel.isType(TYPE_ONE)) { related = rel.getStartNode(); if (related.equals(source)) continue; // we only want INCOMING TYPE_ONE } else if (rel.isType(TYPE_TWO)) { related = rel.getEndNode(); if (related.equals(source)) continue; // we only want OUTGOING TYPE_TWO } else { continue; // should never happen, but makes javac know that related is != null } doSomethingWith( related ); } // With the new API: Node source = ... for (Node related : source.expand( TYPE_ONE, Direction.INCOMING ) .add( TYPE_TWO, Direction.OUTGOING ).nodes()) { doSomethingWith( related ); } The return type of the Node.expand(...)-methods are the new Expansion type, it defaults to expanding to Relationship, but the Expansion.nodes()-method makes it expand to Node. It also contains the add()-methods seen above for specifying RelationshipTypes to include in the expansion. The spelling of this method isn't perfectly decided yet, we are choosing between add, and and include, we want something that reads nicely in the code, but doesn't conflict with keywords in other JVM-languages (and is a keyword in Python, and I think include means something special in Ruby). There is also an Expansion.exlude(RelationshipType)-method for use together with the Node.expandAll(). The Expansion is backed by the newly added companion interface Expander. This is an extension of RelationshipExpander that adds builder capabilities. It turns the functionality of the DefultExpander implementation class (now removed) into an interface in the API. RelationshipExpander is still around as a single method interface, which is useful for when you want to implement your own expansion logic. This API is added to trunk so that we can get feedback from everyone who use the snapshot builds of Neo4j, if the response to this API isn't positive, it will probably be removed before the release of 1.1, so please submit comments in this thread on what you think about this API. Happy Hacking, -- Tobias Ivarsson
Re: [Neo4j] New tentative API in trunk: Expander/Expansion
I like this new API. It is a tiny first step towards making the Java API a little more DSL-like (1% of the way to the current scala and ruby API's :-) My vote is actually for the includes() approach only because *and* is such a widely used keyword. However, a quick test in Ruby showed that while include() and 'and' are used, they can be overridden, and I believe using either in the Java API will not affect their use in the Ruby API. But to be careful, I'd still lean towards the safer includes() option. And, this is Java, after all. Verbosity is expected ;-) (I also noticed that reading the examples with and() correctly indicates that the order of definition is irrelevant, while includes() almost implies that the first relationship type has some kind of precedence. Could it?) On Wed, Jun 23, 2010 at 6:01 PM, Alex Averbuch alex.averb...@gmail.comwrote: Hi, Personally I'd prefer and/not. It's intuitive to any programmer and has the bonus of being much shorter, so long complex expansions will appear less messy in practice. On Wed, Jun 23, 2010 at 5:45 PM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: Did anyone have an opinion on what to call the methods on the Expansion interface that specify which types to expand. Alternative 1) ExpansionT and( RelationshipType type ); ExpansionT and( RelationshipType type, Direction direction ); ExpansionT not( RelationshipType type ); Examples: for (Node node : startNode.expand( KNOWS ) .and( LIKES ) .and( LOVES ) ) { doSomethingWith(node); } ExpansionRelationship expansion = startNode.expand( KNOWS ); expansion = expansion.and( LIKES ); expansion = expansion.and( LOVES ); Alternative 2) ExpansionT including( RelationshipType type ); ExpansionT including( RelationshipType type, Direction direction ); ExpansionT excluding( RelationshipType type ); Examples: for (Node node : startNode.expand( KNOWS ) .including( LIKES ) .including( LOVES ) ) { doSomethingWith(node); } ExpansionRelationship expansion = startNode.expand( KNOWS ); expansion = expansion.including( LIKES ); expansion = expansion.including( LOVES ); Cheers, Tobias On Wed, Jun 23, 2010 at 11:14 AM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: Hi Neo4j enthusiasts! Yesterday I committed an API that Mattias and I have been working on for a few days. It comes in the form of two new interfaces Expander and Expansion (in the org.neo4j.graphdb package), and four new methods in the Node interface (method names starting with expand). The two main problems this API solves are: 1. Adds a clean way for getting related nodes from a source node. 2. Adds a type safe way for declaratively specifying any combination of RelationshipTypes and Directions to expand. This replaces what was actually an anti-pattern, but something we saw people doing a lot: using a depth-one traversal to get the nodes related to a node, without needing to bother with the Relationship interface. Example: // The most convenient way to write it in the past: Node source = ... Traverser traverser = source.traverse( Traverser.Order.DEPTH_FIRST, new StopAtDepth( 1 ), ReturnableEvaluator.ALL_BUT_START_NODE, TYPE_ONE, Direction.INCOMING, TYPE_TWO, Direction.OUTGOING); for (Node related : traverser) { doSomethingWith( related ); } // The previously recommended (and bloated) way of doing it: Node source = ... for (Relationship rel : source.getRelationships( TYPE_ONE, TYPE_TWO )) { Node related; if (rel.isType(TYPE_ONE)) { related = rel.getStartNode(); if (related.equals(source)) continue; // we only want INCOMING TYPE_ONE } else if (rel.isType(TYPE_TWO)) { related = rel.getEndNode(); if (related.equals(source)) continue; // we only want OUTGOING TYPE_TWO } else { continue; // should never happen, but makes javac know that related is != null } doSomethingWith( related ); } // With the new API: Node source = ... for (Node related : source.expand( TYPE_ONE, Direction.INCOMING ) .add( TYPE_TWO, Direction.OUTGOING ).nodes()) { doSomethingWith( related ); } The return type of the Node.expand(...)-methods are the new Expansion type, it defaults to expanding to Relationship, but the Expansion.nodes()-method makes it expand to Node. It also contains the add()-methods seen above for specifying RelationshipTypes to include in the expansion. The spelling of this method isn't perfectly decided yet, we are choosing between add, and and include, we want something that reads nicely in the code, but doesn't conflict with keywords in other
Re: [Neo4j] New tentative API in trunk: Expander/Expansion
On Wed, Jun 23, 2010 at 6:10 PM, Craig Taverner cr...@amanzi.com wrote: (I also noticed that reading the examples with and() correctly indicates that the order of definition is irrelevant, while includes() almost implies that the first relationship type has some kind of precedence. Could it?) I get that feeling as well. Another feeling I get with includes() is that it might be possible to do the following: ExpansionRelationship expansion = startNode.expand( KNOWS ); expansion.includes( LIKES ); expansion.includes( LOVES ); for (Node node : expansion.nodes()) { ... } With includes() one gets the feeling that the above would expand LOVES, LIKES and KNOWS relationships, but it will in fact only expand KNOWS relationships. With and() I don't think that mistake would be as common. Cheers, -- Tobias Ivarsson tobias.ivars...@neotechnology.com Hacker, Neo Technology www.neotechnology.com Cellphone: +46 706 534857 ___ Neo4j mailing list User@lists.neo4j.org https://lists.neo4j.org/mailman/listinfo/user
Re: [Neo4j] New tentative API in trunk: Expander/Expansion
Why not have includes() return the same instance with internal state changed, then the various call options are equivalent. On Jun 23, 2010 6:41 PM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: On Wed, Jun 23, 2010 at 6:10 PM, Craig Taverner cr...@amanzi.com wrote: (I also noticed that r... I get that feeling as well. Another feeling I get with includes() is that it might be possible to do the following: ExpansionRelationship expansion = startNode.expand( KNOWS ); expansion.includes( LIKES ); expansion.includes( LOVES ); for (Node node : expansion.nodes()) { ... } With includes() one gets the feeling that the above would expand LOVES, LIKES and KNOWS relationships, but it will in fact only expand KNOWS relationships. With and() I don't think that mistake would be as common. Cheers, -- Tobias Ivarsson tobias.ivars...@neotechnology.com Hacker, Neo Technology www.neotechnology.com Cel... ___ Neo4j mailing list User@lists.neo4j.org https://lists.neo4j.org/mailman/listinfo/user
Re: [Neo4j] New tentative API in trunk: Expander/Expansion
Because mutable objects are evil. It would for example make it impossible to write classes like this: class Person { private final ExpansionNode friends; Person(Node node) { this.friends = node.expand( FRIEND ).nodes(); } IterablePerson getFriends() { return persons( friends ); } IterablePerson getFriends( final int minimumAge ) { return persons( friends.filterNodes( new PredicateNode() { public boolean accept(Node friend) { return minimumAge = (Integer)friend.getProperty(age); } }) ); } static IterablePerson persons( IterableNode persons ) { return IterableWrapperPerson, Node( persons ) { protected Person underlyingObjectToObject( Node person ) { return new Person( person ); } } } } This might be an acceptable loss though. This could be a case where it is ok to reuse the same object and mutate the internal state. It's something to think about... -tobias On Wed, Jun 23, 2010 at 7:10 PM, Craig Taverner cr...@amanzi.com wrote: Why not have includes() return the same instance with internal state changed, then the various call options are equivalent. On Jun 23, 2010 6:41 PM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: On Wed, Jun 23, 2010 at 6:10 PM, Craig Taverner cr...@amanzi.com wrote: (I also noticed that r... I get that feeling as well. Another feeling I get with includes() is that it might be possible to do the following: ExpansionRelationship expansion = startNode.expand( KNOWS ); expansion.includes( LIKES ); expansion.includes( LOVES ); for (Node node : expansion.nodes()) { ... } With includes() one gets the feeling that the above would expand LOVES, LIKES and KNOWS relationships, but it will in fact only expand KNOWS relationships. With and() I don't think that mistake would be as common. Cheers, -- Tobias Ivarsson tobias.ivars...@neotechnology.com Hacker, Neo Technology www.neotechnology.com Cel... ___ Neo4j mailing list User@lists.neo4j.org https://lists.neo4j.org/mailman/listinfo/user -- Tobias Ivarsson tobias.ivars...@neotechnology.com Hacker, Neo Technology www.neotechnology.com Cellphone: +46 706 534857 ___ Neo4j mailing list User@lists.neo4j.org https://lists.neo4j.org/mailman/listinfo/user
Re: [Neo4j] New tentative API in trunk: Expander/Expansion
Mutable objects have their issues, and yet this is a common and popular paradigm in DSL design. I guess however the point with a DSL is that it is so simple and limited that it compensates for the potential risks. Similar to the dynamic versus static language argument. Now there are ways to reduce the risk. If I remember correctly, one pattern commonly used in the DSL book was to remain strict with model objects, but slack on model builder objects. In this case the Node and Person objects are model objects, and we would put the fancy DSL stuff into a separate class, not as a static method of the Person class. This can help conceptually separate the solid and reliable model from the convenient DSL. On a separate note, perhaps I'm just being slow, but I don't see the aspects of the code below that would be disabled by a mutable builder? Is it the final on 'friends'? That keyword should not stop modifying the contents of friends. ANd you code below does not expose the friends instance to outside influences, so no-one can modify it anyway. What am I missing. On Wed, Jun 23, 2010 at 8:15 PM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: Because mutable objects are evil. It would for example make it impossible to write classes like this: class Person { private final ExpansionNode friends; Person(Node node) { this.friends = node.expand( FRIEND ).nodes(); } IterablePerson getFriends() { return persons( friends ); } IterablePerson getFriends( final int minimumAge ) { return persons( friends.filterNodes( new PredicateNode() { public boolean accept(Node friend) { return minimumAge = (Integer)friend.getProperty(age); } }) ); } static IterablePerson persons( IterableNode persons ) { return IterableWrapperPerson, Node( persons ) { protected Person underlyingObjectToObject( Node person ) { return new Person( person ); } } } } This might be an acceptable loss though. This could be a case where it is ok to reuse the same object and mutate the internal state. It's something to think about... -tobias On Wed, Jun 23, 2010 at 7:10 PM, Craig Taverner cr...@amanzi.com wrote: Why not have includes() return the same instance with internal state changed, then the various call options are equivalent. On Jun 23, 2010 6:41 PM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: On Wed, Jun 23, 2010 at 6:10 PM, Craig Taverner cr...@amanzi.com wrote: (I also noticed that r... I get that feeling as well. Another feeling I get with includes() is that it might be possible to do the following: ExpansionRelationship expansion = startNode.expand( KNOWS ); expansion.includes( LIKES ); expansion.includes( LOVES ); for (Node node : expansion.nodes()) { ... } With includes() one gets the feeling that the above would expand LOVES, LIKES and KNOWS relationships, but it will in fact only expand KNOWS relationships. With and() I don't think that mistake would be as common. Cheers, -- Tobias Ivarsson tobias.ivars...@neotechnology.com Hacker, Neo Technology www.neotechnology.com Cel... ___ Neo4j mailing list User@lists.neo4j.org https://lists.neo4j.org/mailman/listinfo/user -- Tobias Ivarsson tobias.ivars...@neotechnology.com Hacker, Neo Technology www.neotechnology.com Cellphone: +46 706 534857 ___ 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
Re: [Neo4j] New tentative API in trunk: Expander/Expansion
The problem with the code below is that once you've used the Person.getFriends(minAge)-method once, the friends-expansion will have that filter added to it forever (if it's mutable), and that means that you will never be able to get the younger friends of that person. However, reusing an expansion might be so uncommon that it's not even worth bothering with. But if so, it will almost always be used fluent-style, and the use case for being able to mutate it disappears. Ergo, let's keep it immutable, since it enables more use cases. -t On Wed, Jun 23, 2010 at 8:47 PM, Craig Taverner cr...@amanzi.com wrote: Mutable objects have their issues, and yet this is a common and popular paradigm in DSL design. I guess however the point with a DSL is that it is so simple and limited that it compensates for the potential risks. Similar to the dynamic versus static language argument. Now there are ways to reduce the risk. If I remember correctly, one pattern commonly used in the DSL book was to remain strict with model objects, but slack on model builder objects. In this case the Node and Person objects are model objects, and we would put the fancy DSL stuff into a separate class, not as a static method of the Person class. This can help conceptually separate the solid and reliable model from the convenient DSL. On a separate note, perhaps I'm just being slow, but I don't see the aspects of the code below that would be disabled by a mutable builder? Is it the final on 'friends'? That keyword should not stop modifying the contents of friends. ANd you code below does not expose the friends instance to outside influences, so no-one can modify it anyway. What am I missing. On Wed, Jun 23, 2010 at 8:15 PM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: Because mutable objects are evil. It would for example make it impossible to write classes like this: class Person { private final ExpansionNode friends; Person(Node node) { this.friends = node.expand( FRIEND ).nodes(); } IterablePerson getFriends() { return persons( friends ); } IterablePerson getFriends( final int minimumAge ) { return persons( friends.filterNodes( new PredicateNode() { public boolean accept(Node friend) { return minimumAge = (Integer)friend.getProperty(age); } }) ); } static IterablePerson persons( IterableNode persons ) { return IterableWrapperPerson, Node( persons ) { protected Person underlyingObjectToObject( Node person ) { return new Person( person ); } } } } This might be an acceptable loss though. This could be a case where it is ok to reuse the same object and mutate the internal state. It's something to think about... -tobias On Wed, Jun 23, 2010 at 7:10 PM, Craig Taverner cr...@amanzi.com wrote: Why not have includes() return the same instance with internal state changed, then the various call options are equivalent. On Jun 23, 2010 6:41 PM, Tobias Ivarsson tobias.ivars...@neotechnology.com wrote: On Wed, Jun 23, 2010 at 6:10 PM, Craig Taverner cr...@amanzi.com wrote: (I also noticed that r... I get that feeling as well. Another feeling I get with includes() is that it might be possible to do the following: ExpansionRelationship expansion = startNode.expand( KNOWS ); expansion.includes( LIKES ); expansion.includes( LOVES ); for (Node node : expansion.nodes()) { ... } With includes() one gets the feeling that the above would expand LOVES, LIKES and KNOWS relationships, but it will in fact only expand KNOWS relationships. With and() I don't think that mistake would be as common. Cheers, -- Tobias Ivarsson tobias.ivars...@neotechnology.com Hacker, Neo Technology www.neotechnology.com Cel... ___ Neo4j mailing list User@lists.neo4j.org https://lists.neo4j.org/mailman/listinfo/user -- Tobias Ivarsson tobias.ivars...@neotechnology.com Hacker, Neo Technology www.neotechnology.com Cellphone: +46 706 534857 ___ 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 -- Tobias Ivarsson tobias.ivars...@neotechnology.com Hacker, Neo Technology www.neotechnology.com Cellphone: +46 706 534857 ___ Neo4j mailing list User@lists.neo4j.org https://lists.neo4j.org/mailman/listinfo/user