Skip to content

Commit

Permalink
Merge pull request #566 from tinwelint/traversal-fw-additions
Browse files Browse the repository at this point in the history
Additions and changes to the core traversal framework.
  • Loading branch information
systay committed May 30, 2012
2 parents 2853ed9 + 7a11fc2 commit 1790443
Show file tree
Hide file tree
Showing 129 changed files with 6,507 additions and 1,795 deletions.
6 changes: 5 additions & 1 deletion cypher/src/main/scala/org/neo4j/cypher/PathImpl.scala
Expand Up @@ -20,10 +20,10 @@
package org.neo4j.cypher

import java.util.{Iterator => JavaIterator}
import java.lang.{Iterable => JavaIterable}
import scala.collection.JavaConverters._
import org.neo4j.kernel.Traversal
import org.neo4j.graphdb.{Path, Relationship, PropertyContainer, Node}
import java.lang.{Iterable => JavaIterable}

case class PathImpl(pathEntities: PropertyContainer*)
extends org.neo4j.graphdb.Path
Expand Down Expand Up @@ -80,4 +80,8 @@ case class PathImpl(pathEntities: PropertyContainer*)

that.asScala.toList == pathEntities.toList
}

def reverseNodes(): JavaIterable[Node] = entities[Node].reverse.toIterable.asJava

def reverseRelationships(): JavaIterable[Relationship] = entities[Relationship].reverse.toIterable.asJava
}
14 changes: 5 additions & 9 deletions embedded-examples/src/docs/dev/traversal-framework.txt
Expand Up @@ -6,10 +6,6 @@ The Traversal Framework
The http://components.neo4j.org/neo4j/{neo4j-version}/apidocs/org/neo4j/graphdb/traversal/package-summary.html[Neo4j Traversal API] is a callback based, lazily executed way of specifying desired movements through a graph in Java.
Some traversal examples are collected under <<tutorials-java-embedded-traversal>>.

There is also a more restricted way to perform traversals,
http://components.neo4j.org/neo4j/{neo4j-version}/apidocs/org/neo4j/graphdb/Node.html#traverse%28org.neo4j.graphdb.Traverser.Order,%20org.neo4j.graphdb.StopEvaluator,%20org.neo4j.graphdb.ReturnableEvaluator,%20java.lang.Object...%29[Node.traverse()]
is a good starting point to read more about that.

Other options to traverse or query graphs in Neo4j are <<cypher-query-lang,Cypher>> and <<gremlin-plugin,Gremlin>>.

[[tutorial-traversal-concepts]]
Expand All @@ -21,7 +17,7 @@ Here follows a short explanation of all different methods that can modify or add
* _Order_ -- for example depth-first or breadth-first.
* _Uniqueness_ -- visit nodes (relationships, paths) only once.
* _Evaluator_ -- decide what to return and whether to stop or continue traversal beyond the current position.
* A _starting node_ where the traversal will begin.
* _Starting nodes_ where the traversal will begin.

["dot", "graphdb-traversal-description.svg", "meta", scaledwidth="100%"]
----
Expand Down Expand Up @@ -74,7 +70,7 @@ See <<tutorial-traversal-java-api>> for more details.

The traversal framework consists of a few main interfaces in addition to +Node+ and +Relationship+: +TraversalDescription+, +Evaluator+, +Traverser+ and +Uniqueness+ are the main ones.
The +Path+ interface also has a special purpose in traversals, since it is used to represent a position in the graph when evaluating that position.
Furthermore the +RelationshipExpander+ and +Expander+ interfaces are central to traversals, but users of the API rarely need to implement them.
Furthermore the +PathExpander+ (replacing +RelationshipExpander+) and +Expander+ interfaces are central to traversals, but users of the API rarely need to implement them.
There are also a set of interfaces for advanced use, when explicit control over the traversal order is required: +BranchSelector+, +BranchOrderingPolicy+ and +TraversalBranch+.

=== TraversalDescription ===
Expand Down Expand Up @@ -171,9 +167,9 @@ In the traversal API of Neo4j the use of Paths are twofold.
Traversers can return their results in the form of the Paths of the visited positions in the graph that are marked for being returned.
Path objects are also used in the evaluation of positions in the graph, for determining if the traversal should continue from a certain point or not, and whether a certain position should be included in the result set or not.

=== RelationshipExpander ===
=== PathExpander/RelationshipExpander ===

The traversal framework use RelationshipExpanders to discover the relationships that should be followed from a particular node to further branches in the traversal.
The traversal framework use PathExpanders (replacing RelationshipExpander) to discover the relationships that should be followed from a particular path to further branches in the traversal.

=== Expander ===

Expand All @@ -184,7 +180,7 @@ The +Expander+ interface is an extension of the +RelationshipExpander+ interface
The implementation of +TraversalDescription+ uses this to provide methods for defining which relationship types to traverse, this is the usual way a user of the API would define a +RelationshipExpander+ -- by building it internally in the +TraversalDescription+.

All the RelationshipExpanders provided by the Neo4j traversal framework also implement the Expander interface.
For a user of the traversal API it is easier to implement the RelationshipExpander interface, since it only contains one method -- the method for getting the relationships from a node, the methods that the Expander interface adds are just for building new Expanders.
For a user of the traversal API it is easier to implement the PathExpander/RelationshipExpander interface, since it only contains one method -- the method for getting the relationships from a path/node, the methods that the Expander interface adds are just for building new Expanders.

:leveloffset: 3

Expand Down
125 changes: 61 additions & 64 deletions embedded-examples/src/docs/dev/traversal.txt
Expand Up @@ -6,70 +6,6 @@ For reading about traversals, see <<tutorial-traversal>>.

For more examples of traversals, see <<domain-modeling-gallery>>.

== The Matrix ==

This is the first node space we want to traverse into:

image::examples-matrix.png[title="Matrix node space view", scaledwidth="75%"]

[TIP]
The source code of the examples is found here:
https://github.com/neo4j/community/blob/{neo4j-git-tag}/embedded-examples/src/main/java/org/neo4j/examples/Matrix.java[Matrix.java]

.Friends and friends of friends
[snippet,java]
----
component=neo4j-examples
classifier=sources
source=org/neo4j/examples/Matrix.java
tag=get-friends
----

Let's perform the actual traversal and print the results:

[snippet,java]
----
component=neo4j-examples
classifier=sources
source=org/neo4j/examples/Matrix.java
tag=friends-usage
----

Which will give us the following output:

include::matrix-traversal-java-friends.txt[]

.Who coded the Matrix?
[snippet,java]
----
component=neo4j-examples
classifier=sources
source=org/neo4j/examples/Matrix.java
tag=find-hackers
----

Print out the result:

[snippet,java]
----
component=neo4j-examples
classifier=sources
source=org/neo4j/examples/Matrix.java
tag=find--hackers-usage
----

Now we know who coded the Matrix:

include::matrix-traversal-java-hackers.txt[]


== New traversal framework ==

[NOTE]
The following examples use a new experimental traversal API.
It shares the underlying implementation with the old traversal API, so performance-wise they should be equal.
However, expect the new API to evolve and thus undergo changes.

=== The Matrix ===

The traversals from the Matrix example above, this time using the new traversal API:
Expand Down Expand Up @@ -193,3 +129,64 @@ tag=pathPrinter
For options regarding output of a +Path+, see the
http://components.neo4j.org/neo4j/{neo4j-version}/apidocs/org/neo4j/kernel/Traversal.html[Traversal] class.


[NOTE]
The following examples use a deprecated traversal API.
It shares the underlying implementation with the new traversal API, so performance-wise they are equal.
The functionality it provides is very limited in comparison.

== Old traversal API ==

This is the first graph we want to traverse into:

image::examples-matrix.png[title="Matrix node space view", scaledwidth="75%"]

[TIP]
The source code of the examples is found here:
https://github.com/neo4j/community/blob/{neo4j-git-tag}/embedded-examples/src/main/java/org/neo4j/examples/Matrix.java[Matrix.java]

.Friends and friends of friends
[snippet,java]
----
component=neo4j-examples
classifier=sources
source=org/neo4j/examples/Matrix.java
tag=get-friends
----

Let's perform the actual traversal and print the results:

[snippet,java]
----
component=neo4j-examples
classifier=sources
source=org/neo4j/examples/Matrix.java
tag=friends-usage
----

Which will give us the following output:

include::matrix-traversal-java-friends.txt[]

.Who coded the Matrix?
[snippet,java]
----
component=neo4j-examples
classifier=sources
source=org/neo4j/examples/Matrix.java
tag=find-hackers
----

Print out the result:

[snippet,java]
----
component=neo4j-examples
classifier=sources
source=org/neo4j/examples/Matrix.java
tag=find--hackers-usage
----

Now we know who coded the Matrix:

include::matrix-traversal-java-hackers.txt[]
Expand Up @@ -185,7 +185,7 @@ private static Traverser findHackers( final Node startNode )
.relationships( RelTypes.CODED_BY, Direction.OUTGOING )
.relationships( RelTypes.KNOWS, Direction.OUTGOING )
.evaluator(
Evaluators.returnWhereLastRelationshipTypeIs( RelTypes.CODED_BY ) );
Evaluators.includeWhereLastRelationshipTypeIs( RelTypes.CODED_BY ) );
return td.traverse( startNode );
}
// END SNIPPET: find-hackers
Expand Down
Expand Up @@ -37,6 +37,7 @@
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.traversal.Evaluators;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.graphdb.traversal.Traverser;
import org.neo4j.helpers.collection.IterableWrapper;
Expand Down Expand Up @@ -198,8 +199,7 @@ public Iterable<StatusUpdate> getStatus()
// START SNIPPET: getStatusTraversal
TraversalDescription traversal = Traversal.description().
depthFirst().
relationships( NEXT ).
filter( Traversal.returnAll() );
relationships( NEXT );
// END SNIPPET: getStatusTraversal


Expand Down Expand Up @@ -335,8 +335,8 @@ private Iterable<Person> getFriendsByDepth( int depth )
.breadthFirst()
.relationships( FRIEND )
.uniqueness( Uniqueness.NODE_GLOBAL )
.prune( Traversal.pruneAfterDepth( depth ) )
.filter( Traversal.returnAllButStartNode() );
.evaluator( Evaluators.toDepth( depth ) )
.evaluator( Evaluators.excludeStartPosition() );

return createPersonsFromPath( travDesc.traverse( underlyingNode ) );
}
Expand Down
Expand Up @@ -26,6 +26,7 @@

import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.traversal.Evaluators;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.graphdb.traversal.Traverser;
import org.neo4j.helpers.collection.IteratorUtil;
Expand Down Expand Up @@ -59,7 +60,7 @@ private Node getPersonNode()
depthFirst().
relationships( NEXT, Direction.INCOMING ).
relationships( STATUS, Direction.INCOMING ).
filter( Traversal.returnWhereLastRelationshipTypeIs( STATUS ));
evaluator( Evaluators.includeWhereLastRelationshipTypeIs( STATUS ) );

Traverser traverser = traversalDescription.traverse( getUnderlyingNode() );

Expand Down
6 changes: 6 additions & 0 deletions graph-algo/CHANGES.txt
@@ -1,3 +1,9 @@
1.8.M04 (2012-06-07)
--------------------
o AllPaths/AllSimplePaths uses the new bidirectional traversal feature in the traversal framework.
Less relationships now needs to be traversed to find the requested paths.
o Added an implementation of the shortest path algorithm with the bidirectional traversal feature.

1.8.M03 (2012-05-24)
----------------
o Added a FindCommonAncestor graph algorithm
Expand Down

0 comments on commit 1790443

Please sign in to comment.