Neo4j Graph Database Tutorial: How to build a Route Planner and other Examples

January 20th, 2012 by

Often in the life of developer’s life there is a scenario where using a relational database tends to get complicated or sometimes even slow – especially when there are fragments with multiple relationships or multiple connections present. This often leads to complex database queries or desperate software engineers trying to handle those problems with their ORM framework.

A possible solution might be to switch from a relational database to a graph database – and – neo4j is our tool of choice here. In the following tutorial we’re going to implement several examples to demonstrate the strengths of a graph database .. from a route planner to a social graph.

 

Prerequisites

You need to meet the following requirements to run the samples below ..

Adding neo4j to a Maven Project

First a new Maven project …

  • Create a new simple Maven project using your IDE or
    mvn archetype:generate
  • Add the following dependencies needed for neo4j
    <dependency>
     <groupId>org.neo4j</groupId>
     <artifactId>neo4j</artifactId>
     <version>1.5</version>
    </dependency>
  • The neo4j community edition is licensed under the GPLv3 license

Example: Using the Indexer

Often we want to search for a node with a specific property e.g. an id or another attribute without having to traverse the node graph. Luckily for us neo4j comes with my favourite indexer, Lucene and allows to find a node in no time by searching for its indexed properties.

In the following example, we’re creating two nodes – each node has its properties name and id – and we’re adding those properties to the Lucene index so that we’re able to search for these properties..

Referencing nodes via attributes in the Lucene index

Referencing nodes via attributes in the Lucene index

This is my sample named IndexSearchExample

package com.hascode.tutorial;
 
import static com.hascode.tutorial.GraphUtil.cleanUp;
import static com.hascode.tutorial.GraphUtil.registerShutdownHook;
 
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.index.Index;
import org.neo4j.kernel.EmbeddedGraphDatabase;
 
public class IndexSearchExample {
	private static String DB_PATH = "/tmp/neo4j";
 
	public static void main(final String[] args) {
		GraphDatabaseService graphDb = new EmbeddedGraphDatabase(DB_PATH);
		Index<Node> nodeIndex = graphDb.index().forNodes("nodes");
		registerShutdownHook(graphDb);
 
		Transaction tx = graphDb.beginTx();
		try {
			// cleanup first for this tutorial
			cleanUp(graphDb, nodeIndex);
 
			Node userNode1 = graphDb.createNode();
			userNode1.setProperty("id", 1);
			userNode1.setProperty("name", "Peter");
			nodeIndex.add(userNode1, "id", 1);
			nodeIndex.add(userNode1, "name", "Peter");
 
			Node userNode2 = graphDb.createNode();
			userNode2.setProperty("id", 2);
			userNode2.setProperty("name", "Ray");
			nodeIndex.add(userNode2, "id", 2);
			nodeIndex.add(userNode2, "name", "Ray");
 
			tx.success();
 
			System.out.println("searching for user with id=2..");
			Node user = nodeIndex.get("id", 2).getSingle();
			System.out.println("The name of the user with id=2 is: "
					+ user.getProperty("name"));
 
			System.out.println("searching for user with name=Peter..");
			Node user2 = nodeIndex.get("name", "Peter").getSingle();
			System.out.println("The id of the user with name=Peter is: "
					+ user2.getProperty("id"));
		} finally {
			tx.finish();
			graphDb.shutdown();
		}
 
	}
}

I’ve put two convenience methods for this tutorial in a utility class named GraphUtil – it’s just to recreate the node graph and the index on every run. I’m using it in the other examples, too..

package com.hascode.tutorial;
 
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.index.Index;
 
public class GraphUtil {
	public static void cleanUp(final GraphDatabaseService graphDb,
			final Index<Node> nodeIndex) {
		for (Node node : graphDb.getAllNodes()) {
			for (Relationship rel : node.getRelationships()) {
				rel.delete();
			}
			nodeIndex.remove(node);
			node.delete();
		}
 
	}
 
	public static void registerShutdownHook(final GraphDatabaseService graphDb) {
		Runtime.getRuntime().addShutdownHook(new Thread() {
			@Override
			public void run() {
				graphDb.shutdown();
			}
		});
	}
}

Running the example you should see an output similar to this:

searching for user with id=2..
The name of the user with id=2 is: Ray
searching for user with name=Peter..
The id of the user with name=Peter is: 1

Example: Node Traversal

In the next example we want to create – and link some nodes and afterwards traverse them. Nodes with two properties id and name may have a relationship of type “KNOWS”.

A graph of people knowing each other

A graph of people knowing each other

I have created an enum named RelTypes that implements RelationshipType. This is where the relations are defined

package com.hascode.tutorial;
 
import org.neo4j.graphdb.RelationshipType;
 
public enum RelTypes implements RelationshipType {
	KNOWS, LEADS_TO
}

This is my sample class: NodeTraversal

package com.hascode.tutorial;
 
import static com.hascode.tutorial.GraphUtil.registerShutdownHook;
 
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.ReturnableEvaluator;
import org.neo4j.graphdb.StopEvaluator;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.Traverser;
import org.neo4j.graphdb.Traverser.Order;
import org.neo4j.kernel.EmbeddedGraphDatabase;
 
public class NodeTraversalExample {
	private static String DB_PATH = "/tmp/neo4j";
 
	public static void main(final String[] args) {
		GraphDatabaseService graphDb = new EmbeddedGraphDatabase(DB_PATH);
		registerShutdownHook(graphDb);
 
		Transaction tx = graphDb.beginTx();
		try {
			Node peterNode = graphDb.createNode();
			peterNode.setProperty("id", 1);
			peterNode.setProperty("name", "Peter");
 
			Node rayNode = graphDb.createNode();
			rayNode.setProperty("id", 2);
			rayNode.setProperty("name", "Ray");
 
			Node egonNode = graphDb.createNode();
			egonNode.setProperty("id", 3);
			egonNode.setProperty("name", "Egon");
 
			Node winstonNode = graphDb.createNode();
			winstonNode.setProperty("id", 4);
			winstonNode.setProperty("name", "Winston");
 
			Node slimerNode = graphDb.createNode();
			slimerNode.setProperty("id", 5);
			slimerNode.setProperty("name", "Slimer");
 
			Relationship rel1 = peterNode.createRelationshipTo(rayNode,
					RelTypes.KNOWS);
			rel1.setProperty("visibility", "public");
 
			Relationship rel2 = rayNode.createRelationshipTo(egonNode,
					RelTypes.KNOWS);
			rel2.setProperty("visibility", "hidden");
 
			Relationship rel3 = rayNode.createRelationshipTo(winstonNode,
					RelTypes.KNOWS);
			rel3.setProperty("visibility", "public");
 
			Relationship rel4 = winstonNode.createRelationshipTo(slimerNode,
					RelTypes.KNOWS);
			rel4.setProperty("visibility", "public");
 
			tx.success();
 
			System.out.println("traversing nodes for Peter's acquaintances..");
			Traverser acquaintanceTraverser = getAcquaintances(peterNode);
			for (Node acquaintanceNode : acquaintanceTraverser) {
				System.out.println("Peter knows "
						+ acquaintanceNode.getProperty("name") + " (id: "
						+ acquaintanceNode.getProperty("id") + ") at depth: "
						+ acquaintanceTraverser.currentPosition().depth());
			}
		} finally {
			tx.finish();
		}
 
		graphDb.shutdown();
	}
 
	private static Traverser getAcquaintances(final Node personNode) {
		return personNode.traverse(Order.BREADTH_FIRST,
				StopEvaluator.END_OF_GRAPH,
				ReturnableEvaluator.ALL_BUT_START_NODE, RelTypes.KNOWS,
				Direction.OUTGOING);
	}
}

Running the sample, the following output should appear

traversing nodes for Peter's acquaintances..
Peter knows Ray (id: 2) at depth: 1
Peter knows Egon (id: 3) at depth: 2
Peter knows Winston (id: 4) at depth: 2
Peter knows Slimer (id: 5) at depth: 3

Example: Node Filtering

In the following example we’re traversing the nodes given some additional criteria – only relations with a property visibility=public should be traversed..

Graph of people

Graph of people with a visibility attribute

This is my example – FilteredNodeTraversalExample

package com.hascode.tutorial;
 
import static com.hascode.tutorial.GraphUtil.registerShutdownHook;
 
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.ReturnableEvaluator;
import org.neo4j.graphdb.StopEvaluator;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.TraversalPosition;
import org.neo4j.graphdb.Traverser;
import org.neo4j.graphdb.Traverser.Order;
import org.neo4j.kernel.EmbeddedGraphDatabase;
 
public class FilteredNodeTraversalExample {
	private static String DB_PATH = "/tmp/neo4j";
 
	public static void main(final String[] args) {
		GraphDatabaseService graphDb = new EmbeddedGraphDatabase(DB_PATH);
		registerShutdownHook(graphDb);
 
		Transaction tx = graphDb.beginTx();
		try {
			Node peterNode = graphDb.createNode();
			peterNode.setProperty("id", 1);
			peterNode.setProperty("name", "Peter");
 
			Node rayNode = graphDb.createNode();
			rayNode.setProperty("id", 2);
			rayNode.setProperty("name", "Ray");
 
			Node egonNode = graphDb.createNode();
			egonNode.setProperty("id", 3);
			egonNode.setProperty("name", "Egon");
 
			Node winstonNode = graphDb.createNode();
			winstonNode.setProperty("id", 4);
			winstonNode.setProperty("name", "Winston");
 
			Node slimerNode = graphDb.createNode();
			slimerNode.setProperty("id", 5);
			slimerNode.setProperty("name", "Slimer");
 
			Relationship rel1 = peterNode.createRelationshipTo(rayNode,
					RelTypes.KNOWS);
			rel1.setProperty("visibility", "public");
 
			Relationship rel2 = rayNode.createRelationshipTo(egonNode,
					RelTypes.KNOWS);
			rel2.setProperty("visibility", "hidden");
 
			Relationship rel3 = rayNode.createRelationshipTo(winstonNode,
					RelTypes.KNOWS);
			rel3.setProperty("visibility", "public");
 
			Relationship rel4 = winstonNode.createRelationshipTo(slimerNode,
					RelTypes.KNOWS);
			rel4.setProperty("visibility", "public");
 
			tx.success();
 
			System.out
					.println("traversing nodes for Peter's public acquaintances..");
			Traverser acquaintanceTraverser = getAcquaintances(peterNode);
			for (Node acquaintanceNode : acquaintanceTraverser) {
				System.out.println("Peter knows "
						+ acquaintanceNode.getProperty("name") + " (id: "
						+ acquaintanceNode.getProperty("id") + ") at depth: "
						+ acquaintanceTraverser.currentPosition().depth());
			}
		} finally {
			tx.finish();
		}
 
		graphDb.shutdown();
	}
 
	private static Traverser getAcquaintances(final Node personNode) {
		return personNode.traverse(Order.BREADTH_FIRST,
				StopEvaluator.END_OF_GRAPH, new ReturnableEvaluator() {
					@Override
					public boolean isReturnableNode(
							final TraversalPosition currentPos) {
						return !currentPos.isStartNode()
								&& currentPos.lastRelationshipTraversed()
										.hasProperty("visibility")
								&& "public".equals(currentPos
										.lastRelationshipTraversed()
										.getProperty("visibility"));
					}
				}, RelTypes.KNOWS, Direction.OUTGOING);
	}
}

And this is the expected output

traversing nodes for Peter's public acquaintances..
Peter knows Ray (id: 2) at depth: 1
Peter knows Winston (id: 4) at depth: 2
Peter knows Slimer (id: 5) at depth: 3

Example: Building a Route Planner

In the following example we’re simulating a railway network – railway stations are connected with other railway stations and each connection between two stations has a property: the distance (in miles).

We’re using Dijkstras algorithm to calculate the shortest route from London to Bristol and Northampton to Brighton here.

Railway Network Nodes

Railway Network Nodes

And this is the sample code

package com.hascode.tutorial;
 
import static com.hascode.tutorial.GraphUtil.registerShutdownHook;
 
import org.neo4j.graphalgo.GraphAlgoFactory;
import org.neo4j.graphalgo.PathFinder;
import org.neo4j.graphalgo.WeightedPath;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.index.Index;
import org.neo4j.kernel.EmbeddedGraphDatabase;
import org.neo4j.kernel.Traversal;
 
public class RailroadExample {
	private static String DB_PATH = "/tmp/neo4j";
 
	public static void main(final String[] args) {
		GraphDatabaseService graphDb = new EmbeddedGraphDatabase(DB_PATH);
		registerShutdownHook(graphDb);
		Index<Node> nodeIndex = graphDb.index().forNodes("nodes");
 
		Transaction tx = graphDb.beginTx();
		try {
			Node londonNode = graphDb.createNode();
			londonNode.setProperty("name", "London");
			nodeIndex.add(londonNode, "name", "London");
 
			Node brightonNode = graphDb.createNode();
			brightonNode.setProperty("name", "Brighton");
			nodeIndex.add(brightonNode, "name", "Brighton");
 
			Node portsmouthNode = graphDb.createNode();
			portsmouthNode.setProperty("name", "Portsmouth");
			nodeIndex.add(portsmouthNode, "name", "Portsmouth");
 
			Node bristolNode = graphDb.createNode();
			bristolNode.setProperty("name", "Bristol");
			nodeIndex.add(bristolNode, "name", "Bristol");
 
			Node oxfordNode = graphDb.createNode();
			oxfordNode.setProperty("name", "Oxford");
			nodeIndex.add(oxfordNode, "name", "Oxford");
 
			Node gloucesterNode = graphDb.createNode();
			gloucesterNode.setProperty("name", "Gloucester");
			nodeIndex.add(gloucesterNode, "name", "Gloucester");
 
			Node northamptonNode = graphDb.createNode();
			northamptonNode.setProperty("name", "Northampton");
			nodeIndex.add(northamptonNode, "name", "Northampton");
 
			Node southamptonNode = graphDb.createNode();
			southamptonNode.setProperty("name", "Southampton");
			nodeIndex.add(southamptonNode, "name", "Southampton");
 
			// london -> brighton ~ 52mi
			Relationship r1 = londonNode.createRelationshipTo(brightonNode,
					RelTypes.LEADS_TO);
			r1.setProperty("distance", 52);
 
			// brighton -> portsmouth ~ 49mi
			Relationship r2 = brightonNode.createRelationshipTo(portsmouthNode,
					RelTypes.LEADS_TO);
			r2.setProperty("distance", 49);
 
			// portsmouth -> southampton ~ 20mi
			Relationship r3 = portsmouthNode.createRelationshipTo(
					southamptonNode, RelTypes.LEADS_TO);
			r3.setProperty("distance", 20);
 
			// london -> oxford ~95mi
			Relationship r4 = londonNode.createRelationshipTo(oxfordNode,
					RelTypes.LEADS_TO);
			r4.setProperty("distance", 95);
 
			// oxford -> southampton ~66mi
			Relationship r5 = oxfordNode.createRelationshipTo(southamptonNode,
					RelTypes.LEADS_TO);
			r5.setProperty("distance", 66);
 
			// oxford -> northampton ~45mi
			Relationship r6 = oxfordNode.createRelationshipTo(northamptonNode,
					RelTypes.LEADS_TO);
			r6.setProperty("distance", 45);
 
			// northampton -> bristol ~114mi
			Relationship r7 = northamptonNode.createRelationshipTo(bristolNode,
					RelTypes.LEADS_TO);
			r7.setProperty("distance", 114);
 
			// southampton -> bristol ~77mi
			Relationship r8 = southamptonNode.createRelationshipTo(bristolNode,
					RelTypes.LEADS_TO);
			r8.setProperty("distance", 77);
 
			// northampton -> gloucester ~106mi
			Relationship r9 = northamptonNode.createRelationshipTo(
					gloucesterNode, RelTypes.LEADS_TO);
			r9.setProperty("distance", 106);
 
			// gloucester -> bristol ~35mi
			Relationship r10 = gloucesterNode.createRelationshipTo(bristolNode,
					RelTypes.LEADS_TO);
			r10.setProperty("distance", 35);
 
			tx.success();
 
			System.out
					.println("searching for the shortest route from London to Bristol..");
			PathFinder<WeightedPath> finder = GraphAlgoFactory.dijkstra(
					Traversal.expanderForTypes(RelTypes.LEADS_TO,
							Direction.BOTH), "distance");
 
			WeightedPath path = finder.findSinglePath(londonNode, bristolNode);
			System.out.println("London - Bristol with a distance of: "
					+ path.weight() + " and via: ");
			for (Node n : path.nodes()) {
				System.out.print(" " + n.getProperty("name"));
			}
 
			System.out
					.println("\nsearching for the shortest route from Northampton to Brighton..");
			path = finder.findSinglePath(northamptonNode, brightonNode);
			System.out.println("Northampton - Brighton with a distance of: "
					+ path.weight() + " and via: ");
			for (Node n : path.nodes()) {
				System.out.print(" " + n.getProperty("name"));
			}
 
		} finally {
			tx.finish();
		}
 
		graphDb.shutdown();
	}
}

Running the code gives us the following output

searching for the shortest route from London to Bristol..
London - Bristol with a distance of: 198.0 and via:
 London Brighton Portsmouth Southampton Bristol
searching for the shortest route from Northampton to Brighton..
Northampton - Brighton with a distance of: 180.0 and via:
 Northampton Oxford Southampton Portsmouth Brighton

Example: Mapping Users to Roles to Permissions

As another example we’re going to implement a system that assigns users to roles and permissions to roles.

There are three different roles: guest, user and admin and three permissions: read, write and administer.

We’re now building a graph to map the different permissions but you might ask where there is the advantage of using a graph for this?

We could make the scenario a bit more difficult and say that there are combined roles .. e.g. role root is a part of the role admin and the permissions read, write and administer are all parts of a permission named godmode – using a graph there we only need to descend the graph until we’ve got all permissions for the user mapped by the different possible paths in the graph.

User-Roles-Permissions mapped using a Graph

User-Roles-Permissions mapped using a Graph

We’re using a fresh enum to define our relation types here UserRelTypes

package com.hascode.tutorial;
 
import org.neo4j.graphdb.RelationshipType;
 
public enum UserRelTypes implements RelationshipType {
	MEMBER_OF, HAS_ROLE, HAS_PERMISSION
}

Now to create the node structure

package com.hascode.tutorial;
 
import static com.hascode.tutorial.GraphUtil.cleanUp;
import static com.hascode.tutorial.GraphUtil.registerShutdownHook;
 
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.ReturnableEvaluator;
import org.neo4j.graphdb.StopEvaluator;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.Traverser;
import org.neo4j.graphdb.index.Index;
import org.neo4j.kernel.EmbeddedGraphDatabase;
 
public class UserRolePermissionExample {
	private static String DB_PATH = "/tmp/neo4j";
 
	public static void main(final String[] args) {
		GraphDatabaseService graphDb = new EmbeddedGraphDatabase(DB_PATH);
		registerShutdownHook(graphDb);
		Index<Node> nodeIndex = graphDb.index().forNodes("nodes");
 
		Transaction tx = graphDb.beginTx();
		try {
			// cleanup first for this tutorial
			cleanUp(graphDb, nodeIndex);
 
			// 1. define possible permissions
			// permission:read
			Node permissionRead = graphDb.createNode();
			permissionRead.setProperty("permission", "read");
			nodeIndex.add(permissionRead, "permission", "read");
 
			// permission:write
			Node permissionWrite = graphDb.createNode();
			permissionWrite.setProperty("permission", "write");
			nodeIndex.add(permissionWrite, "permission", "write");
 
			// permission:administer
			Node permissionAdminister = graphDb.createNode();
			permissionAdminister.setProperty("permission", "administer");
			nodeIndex.add(permissionAdminister, "permission", "administer");
 
			// 2. define possible roles
			// role:guest
			Node roleGuest = graphDb.createNode();
			roleGuest.setProperty("role", "guest");
			nodeIndex.add(roleGuest, "role", "guest");
 
			// role:user
			Node roleUser = graphDb.createNode();
			roleUser.setProperty("role", "user");
			nodeIndex.add(roleUser, "role", "user");
 
			Node roleAdmin = graphDb.createNode();
			roleAdmin.setProperty("role", "admin");
			nodeIndex.add(roleAdmin, "role", "admin");
 
			// 3. assign permissions to roles
			// guests are only allowed to read
			roleGuest.createRelationshipTo(permissionRead,
					UserRelTypes.HAS_PERMISSION);
 
			// users my read and write
			roleUser.createRelationshipTo(permissionRead,
					UserRelTypes.HAS_PERMISSION);
			roleUser.createRelationshipTo(permissionWrite,
					UserRelTypes.HAS_PERMISSION);
 
			// administrators may read, write and administer
			roleAdmin.createRelationshipTo(permissionRead,
					UserRelTypes.HAS_PERMISSION);
			roleAdmin.createRelationshipTo(permissionWrite,
					UserRelTypes.HAS_PERMISSION);
			roleAdmin.createRelationshipTo(permissionAdminister,
					UserRelTypes.HAS_PERMISSION);
 
			// 4. finally create some users and assign roles
			// egon is a guest
			Node egon = graphDb.createNode();
			egon.setProperty("name", "Egon");
			nodeIndex.add(egon, "name", "Egon");
			egon.createRelationshipTo(roleGuest, UserRelTypes.HAS_ROLE);
 
			// winston is a user
			Node winston = graphDb.createNode();
			winston.setProperty("name", "Winston");
			nodeIndex.add(winston, "name", "Winston");
			winston.createRelationshipTo(roleUser, UserRelTypes.HAS_ROLE);
 
			// slimer is - of course - an admin
			Node slimer = graphDb.createNode();
			slimer.setProperty("name", "Slimer");
			nodeIndex.add(slimer, "name", "Slimer");
			slimer.createRelationshipTo(roleAdmin, UserRelTypes.HAS_ROLE);
 
			tx.success();
 
			System.out
					.println("Looking up permissions for user with name=Winston");
			Node userWinston = nodeIndex.get("name", "Winston").getSingle();
			Traverser permissionTraverser = getPermissionTraverser(userWinston);
			printPermissions(userWinston, permissionTraverser);
 
			System.out
					.println("Looking up permissions for user with name=Slimer");
			Node userSlimer = nodeIndex.get("name", "Slimer").getSingle();
			permissionTraverser = getPermissionTraverser(userSlimer);
			printPermissions(userSlimer, permissionTraverser);
		} finally {
			tx.finish();
		}
 
		graphDb.shutdown();
	}
 
	private static void printPermissions(final Node userNode,
			final Traverser permissionTraverser) {
		final String userName = (String) userNode.getProperty("name");
		for (Node node : permissionTraverser) {
			if (node.hasProperty("role")) {
				System.out.println(userName + " has the role: "
						+ node.getProperty("role"));
			}
			if (node.hasProperty("permission")) {
				System.out.println(userName + " has permission: "
						+ node.getProperty("permission") + " at depth: "
						+ (permissionTraverser.currentPosition().depth() - 1));
			}
		}
	}
 
	private static Traverser getPermissionTraverser(final Node userNode) {
		return userNode.traverse(Traverser.Order.DEPTH_FIRST,
				StopEvaluator.END_OF_GRAPH,
				ReturnableEvaluator.ALL_BUT_START_NODE, UserRelTypes.HAS_ROLE,
				Direction.OUTGOING, UserRelTypes.HAS_PERMISSION,
				Direction.OUTGOING);
	}
}

And this is the output

Looking up permissions for user with name=Winston
Winston has the role: user
Winston has permission: read at depth: 1
Winston has permission: write at depth: 1
Looking up permissions for user with name=Slimer
Slimer has the role: admin
Slimer has permission: read at depth: 1
Slimer has permission: write at depth: 1
Slimer has permission: administer at depth: 1

Tutorial Sources

I have put the source from this tutorial on my Bitbucket repository – download it there or check it out using Mercurial:

hg clone https://bitbucket.org/hascode/neo4j-tutorial

yED Graph Editor

All the graph drawing in this tutorial were made using the free yED graph editor from  yWorks – it’s really easy and comfortable to use and has some nice features!

You’re able to download it here or simply start the editor from here using Java Web Start.

The yED Graph Editor

The yED Graph Editor

Troubleshooting

  • “Exception in thread “main” java.util.NoSuchElementException: More than one element in org.neo4j.index.impl.lucene.LuceneIndex$1@12789d2. First element is ‘Node[2]‘ and the second element is ‘Node[4]‘
    at org.neo4j.helpers.collection.IteratorUtil.singleOrNull(IteratorUtil.java:116)
    at org.neo4j.index.impl.lucene.IdToEntityIterator.getSingle(IdToEntityIterator.java:88)
    at org.neo4j.index.impl.lucene.IdToEntityIterator.getSingle(IdToEntityIterator.java:32)
    at com.hascode.tutorial.IndexSearchExample.main(IndexSearchExample.java:45)”
    – if you’re running the tutorial sources or you’re just experimenting – you eventually might need to reset your graph or your node index – the following method helps you there

    public void cleanUp(final GraphDatabaseService graphDb,
     final Index<Node> nodeIndex) {
     for (Node node : graphDb.getAllNodes()) {
     for (Relationship rel : node.getRelationships()) {
     rel.delete();
     }
     nodeIndex.remove(node);
     node.delete();
     }

Resources

package com.hascode.tutorial;

import static com.hascode.tutorial.GraphUtil.cleanUp;
import static com.hascode.tutorial.GraphUtil.registerShutdownHook;

import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.index.Index;
import org.neo4j.kernel.EmbeddedGraphDatabase;

public class IndexSearchExample {
private static String DB_PATH = “/tmp/neo4j”;

public static void main(final String[] args) {
GraphDatabaseService graphDb = new EmbeddedGraphDatabase(DB_PATH);
Index<Node> nodeIndex = graphDb.index().forNodes(“nodes”);
registerShutdownHook(graphDb);

Transaction tx = graphDb.beginTx();
try {
// cleanup first for this tutorial
cleanUp(graphDb, nodeIndex);

Node userNode1 = graphDb.createNode();
userNode1.setProperty(“id”, 1);
userNode1.setProperty(“name”, “Peter”);
nodeIndex.add(userNode1, “id”, 1);
nodeIndex.add(userNode1, “name”, “Peter”);

Node userNode2 = graphDb.createNode();
userNode2.setProperty(“id”, 2);
userNode2.setProperty(“name”, “Ray”);
nodeIndex.add(userNode2, “id”, 2);
nodeIndex.add(userNode2, “name”, “Ray”);

tx.success();

System.out.println(“searching for user with id=2..”);
Node user = nodeIndex.get(“id”, 2).getSingle();
System.out.println(“The name of the user with id=2 is: ”
+ user.getProperty(“name”));

System.out.println(“searching for user with name=Peter..”);
Node user2 = nodeIndex.get(“name”, “Peter”).getSingle();
System.out.println(“The id of the user with name=Peter is: ”
+ user2.getProperty(“id”));
} finally {
tx.finish();
graphDb.shutdown();
}

}
}

Tags: , , , , , , , ,

11 Responses to “Neo4j Graph Database Tutorial: How to build a Route Planner and other Examples”

  1. Peter Says:

    Thanks for your work on this example. Did you test the route planner on real world data? Because I guess it (dijkstra and your ram/cpu) won’t scale beyond the size of a city with this approach … would be nice if you can try it though :) (importing some osm etc)

  2. micha kops Says:

    You’re probably right but it sounds interesting as an experiment indeed :)

  3. charlie Says:

    The depth reported for NodeTraversalExample and FilteredNodeTraversalExample seems to be wrong, It always reports depth of 3. For NodeTraversalExample I made some changes to the traverser

    Traverser friendsTraverser = getFriends( peterNode );
    for ( Node friendNode : friendsTraverser )
    {
    System.out.println( “Peter knows ” +
    friendNode.getProperty( “name” ) + ” (” +
    friendNode.getProperty(“id”) + “) at depth ” +
    friendsTraverser.currentPosition().depth()
    );
    }

    private static Traverser getFriends( final Node personNode )
    {
    return personNode.traverse(
    Order.BREADTH_FIRST,
    stopEvaluator,
    ReturnableEvaluator.ALL_BUT_START_NODE,
    RelTypes.KNOWS,
    Direction.OUTGOING );
    }

    and get the following which is more what I expected (I’m assuming depth is distance away from start node):

    traversing nodes for Peter’s acquaintances..
    Peter knows Ray (2) at depth 1
    Peter knows Egon (3) at depth 2
    Peter knows Winston (4) at depth 2
    Peter knows Slimer (5) at depth 3

  4. micha kops Says:

    thanks a lot for mentioning! .. somehow the findAllNodes method has slipped into those two examples :)

  5. Gabriel Ozeas Says:

    Awesome tutorial, congratulations! I’m looking for some weeks for an good introductions!

  6. Nirmalya Sengupta Says:

    A very good example. yED graphing utility seems to be very useful for my purposes. Many thanks for both of these.

  7. frank Says:

    Hi micha!
    Thanks for your tutorial, I like it!

    I started with yED and find the resulting .graphml very complicated.
    Then I used your tutorial sources and things were much clearer.

    Now I’m wonderning: Has you a solution to “generate?” the .graphml sources from a neoDB to be edited by yED?

    Now I’m windering again: How could I update the neoDB with changed .graphml data?

    Thanks again.
    Frank

  8. Rahul Deshmukh Says:

    Hi,
    I saw a very good example on this website for Building a Route Planner in Neo4j. I want to know where i wil get the complete project for this with librabry files? I want to use this example and in additionally i want improve it by building benchmark in it.
    Thanks

    regards,
    Raj

  9. micha kops Says:

    Hi Rahul,

    please have a look at “Tutorial Sources” – you may download the sources from my linked repository there. To build and run the examples all you need is a JDK and Maven.

    Best regards

    Micha

  10. Rahul Deshmukh Says:

    Hi Micha,
    Thanks for your reply. I saw the tutorial sources you send me but i have not seen the building router and planning example in that. Can you please tell me where should i check ?
    Thank You.

    regards,
    Rhaul

  11. micha kops Says:

    Hi, the following command runs the railroad example:
    mvn exec:java -Dexec.mainClass=com.hascode.tutorial.RailroadExample

Search
Categories