Java Tutorial on Neo4j – A Next Generation Graph Database

Neo4j is a Graph Database. A Graph database stores data in graph. Graphs have nodes which have one or more properties. The two nodes are connected by relationships. Relationships have one or more properties and helps in organizing the graphs. The Graphs can be traversed by different graph algorithms.

Features

  1.  Neo4j is a graph database.
  2. Highly available.
  3. Supports ACID transactions
  4. Scales to billions of node.
  5. Very high speed quering and graph traversal algorithms.

Setting Up Neo4j

You can use neo4j as embedded entity in your code. But for this tutorial we will download the server and start it using our command line.

  1. Download the latest release from http://neo4j.org/download.
  2. Select the appropriate version for your platform
  3. Extract the contents of the archive. We will be referring to  to the top-level extracted directory as <neo4j-home>
  4. Open your command window and navigate to <neo4j-home>/bin
  5. for Linux/MacOS, run <neo4j-home>/bin/neo4j start
  6. for Windows, run <neo4j-home>\bin\Neo4j.bat
  7. Visit http://localhost:7474 to verify that your instance has started and running peacefully.

For more options visit this url

http://docs.neo4j.org/chunked/milestone/server-installation.html

Once our neo4j is up and running we will see how to add nodes, properties and relationships using its java apis.

Getting the code for this tutorial

You can get the code for this tutorial from following svn url

https://www.assembla.com/code/weblog4j/subversion/nodes/29/SpringDemos/trunk

The project contains lots of other example, for neo4j example check package com.aranin.spring.neo4j

Downloading dependencies

Maven users can include following in their POM.

<dependency>
    <groupId>org.neo4j</groupId>
    <artifactId>neo4j</artifactId>
    <version>1.9.1</version>
</dependency>

Neo4j exposes its functions via set of REST API’s so for that we will be using apache HttpCient libraries. You can use any rest client api for your purpose. For http client use following maven dependencies

<dependency>
      <groupId>commons-httpclient</groupId>
      <artifactId>commons-httpclient</artifactId>
      <version>3.1</version>
</dependency>

<dependency>
     <groupId>org.apache.httpcomponents</groupId>
     <artifactId>httpclient</artifactId>
     <version>4.1.3</version>
     <scope>compile</scope>
</dependency>

<dependency>
     <groupId>org.apache.httpcomponents</groupId>
     <artifactId>httpmime</artifactId>
     <version>4.1.3</version>
     <scope>compile</scope>
</dependency>

Getting started with code

Once the neo4j server is up and running we can start to add nodes, properties and relationships using its rest API. Please note that node4j is running at http://localhost:7474. We will be using it as SERVER_ROOT_URI. So lets get the ball rolling.

Checking the server status

We can make a get request to the server root uri to check if server is running or not.

public int getServerStatus(){
	int status = 500;
	try{
	    //SERVER_ROOT_URI = 'http://localhost:7474' 
		String url = SERVER_ROOT_URI;
		HttpClient client = new HttpClient();
		GetMethod mGet =   new GetMethod(url);
		status = client.executeMethod(mGet);
		mGet.releaseConnection( );
	}catch(Exception e){
	System.out.println("Exception in connecting to neo4j : " + e);
	}

	return status;
}

If you invoke this method and everything is fine then you will get back server status of 200.

Creating a Node

We can make a POST request to <server-root-uri>//db/data/node. This will create a node in the node4j database. Following things should be noticed here.

  1. The REST URL is <server-root-uri>//db/data/node
  2. It accepts POST request.
  3. It accepts and sends json data.
  4. Upon successful creation of node the web-service returns 201 Create response.
  5. It also sends back URI of node in location header of response.

So lets check out the createNode() method

public String createNode(){
        String output = null;
        String location = null;
        try{
            String nodePointUrl = this.SERVER_ROOT_URI + "/db/data/node";
            HttpClient client = new HttpClient();
            PostMethod mPost = new PostMethod(nodePointUrl);

            /**
             * set headers
             */
            Header mtHeader = new Header();
            mtHeader.setName("content-type");
            mtHeader.setValue("application/json");
            mtHeader.setName("accept");
            mtHeader.setValue("application/json");
            mPost.addRequestHeader(mtHeader);

            /**
             * set json payload
             */
            StringRequestEntity requestEntity = new StringRequestEntity("{}",
                                                                        "application/json",
                                                                        "UTF-8");
            mPost.setRequestEntity(requestEntity);
            int satus = client.executeMethod(mPost);
            output = mPost.getResponseBodyAsString( );
            Header locationHeader =  mPost.getResponseHeader("location");
            location = locationHeader.getValue();
            mPost.releaseConnection( );
            System.out.println("satus : " + satus);
            System.out.println("location : " + location);
            System.out.println("output : " + output);
        }catch(Exception e){
        System.out.println("Exception in creating node in neo4j : " + e);
        }

        return location;
    }

The method is quite simple. All we have done is to create a post connection to the node service and send an empty json object to it. You can also visit the webadmin and verify that node has been created. Check out the uri of node created. It should be in form 

http://localhost:7474/db/data/node/1

Adding property to the node

So now we have created an empty node. Now we can add properties to it. For this neo4j provides another rest api  NodeURI + “/properties/” + propertyName. For example if you want to add “name” property to above created node the service uri will look like

http://localhost:7474/db/data/node/1/properties/name

The properties service is a PUT service and upon successful completion it returns “204 No Content” response. Like its create pear this service also accepts and sends json data format. So lets check out code for adding property for node.

public void addProperty(String nodeURI,
                            String propertyName,
                            String propertyValue){
        String output = null;

        try{
            String nodePointUrl = nodeURI + "/properties/" + propertyName;
            HttpClient client = new HttpClient();
            PutMethod mPut = new PutMethod(nodePointUrl);

            /**
             * set headers
             */
            Header mtHeader = new Header();
            mtHeader.setName("content-type");
            mtHeader.setValue("application/json");
            mtHeader.setName("accept");
            mtHeader.setValue("application/json");
            mPut.addRequestHeader(mtHeader);

            /**
             * set json payload
             */
            String jsonString = """ + propertyValue + """;
            StringRequestEntity requestEntity = new StringRequestEntity(jsonString,
                                                                        "application/json",
                                                                        "UTF-8");
            mPut.setRequestEntity(requestEntity);
            int satus = client.executeMethod(mPut);
            output = mPut.getResponseBodyAsString( );

            mPut.releaseConnection( );
            System.out.println("satus : " + satus);
            System.out.println("output : " + output);
        }catch(Exception e){
         System.out.println("Exception in creating node in neo4j : " + e);
        }

    }

Please note how the url is created. We pass in the node url which is returned by createNode() method and then append it with properties/<propertyName>. The value of property is sent as json payload , jsonString = “\”" + propertyValue + “\”" , which is set in PUT request. Once you add a property you can go and check it in the webadmin.

Creating a relationship

Now that we have created couple of node lets create a relationship between them.

  1. For this we have to invoke following rest web service. <nodeurl>/relationships where nodeurl is the source node from where relationship arises.
  2. This web-service receives accepts data through POST request.
  3. It accept json data and sends json data back. Format of json payload is                    { “to” : “http://localhost:7474/db/data/node/2″, “type” : “friend”, “data” : { “married” : “yes”,”since” : “2005″ } }
  4. Upon successful completion of request it sends back 201 status code.
  5. It also sends back url of created relation in location header of response.

Lets check out code for such request

public String addRelationship(String startNodeURI,
                                   String endNodeURI,
                                   String relationshipType,
                                   String jsonAttributes){
        String output = null;
        String location = null;
        try{
            String fromUrl = startNodeURI + "/relationships";
            System.out.println("from url : " + fromUrl);

            String relationshipJson = generateJsonRelationship( endNodeURI,
                                                                relationshipType,
                                                                jsonAttributes );

            System.out.println("relationshipJson : " + relationshipJson);

            HttpClient client = new HttpClient();
            PostMethod mPost = new PostMethod(fromUrl);

            /**
             * set headers
             */
            Header mtHeader = new Header();
            mtHeader.setName("content-type");
            mtHeader.setValue("application/json");
            mtHeader.setName("accept");
            mtHeader.setValue("application/json");
            mPost.addRequestHeader(mtHeader);

            /**
             * set json payload
             */
            StringRequestEntity requestEntity = new StringRequestEntity(relationshipJson,
                                                                        "application/json",
                                                                        "UTF-8");
            mPost.setRequestEntity(requestEntity);
            int satus = client.executeMethod(mPost);
            output = mPost.getResponseBodyAsString( );
            Header locationHeader =  mPost.getResponseHeader("location");
            location = locationHeader.getValue();
            mPost.releaseConnection( );
            System.out.println("satus : " + satus);
            System.out.println("location : " + location);
            System.out.println("output : " + output);
        }catch(Exception e){
             System.out.println("Exception in creating node in neo4j : " + e);
        }

        return location;

    }

    private String generateJsonRelationship(String endNodeURL,
                                            String relationshipType,
                                            String ... jsonAttributes) {
        StringBuilder sb = new StringBuilder();
        sb.append("{ "to" : "");
        sb.append(endNodeURL);
        sb.append("", ");

        sb.append(""type" : "");
        sb.append(relationshipType);
        if(jsonAttributes == null || jsonAttributes.length < 1) {
            sb.append(""");
        } else {
            sb.append("", "data" : ");
            for(int i = 0; i < jsonAttributes.length; i++) {
                sb.append(jsonAttributes[i]);
                if(i < jsonAttributes.length -1) { // Miss off the final comma
                    sb.append(", ");
                }
            }
        }

        sb.append(" }");
        return sb.toString();
    }

Please check the generateJsonRelationship method. This method generates the json payload that has to be sent with the request.

Creating properties for Relationship

Once the relationship is created we can assign it properties. This can be done in following manner

  1. Invoking following rest web-service <relationshipurl>/properties. eg http://localhost:7474/db/data/relationship/1/properties
  2. This web-service can b invoked by PUT request.
  3. It accepts and sends back json response.
  4. Upon successful completion of request it sends back 204 status code in response.

Lets check out the code for this

private void addPropertyToRelation( String relationshipUri,
                                        String propertyName,
                                        String propertyValue ){

        String output = null;

        try{
            String relPropUrl = relationshipUri + "/properties";
            HttpClient client = new HttpClient();
            PutMethod mPut = new PutMethod(relPropUrl);

            /**
             * set headers
             */
            Header mtHeader = new Header();
            mtHeader.setName("content-type");
            mtHeader.setValue("application/json");
            mtHeader.setName("accept");
            mtHeader.setValue("application/json");
            mPut.addRequestHeader(mtHeader);

            /**
             * set json payload
             */
            String jsonString = toJsonNameValuePairCollection(propertyName,propertyValue );
            StringRequestEntity requestEntity = new StringRequestEntity(jsonString,
                                                                        "application/json",
                                                                        "UTF-8");
            mPut.setRequestEntity(requestEntity);
            int satus = client.executeMethod(mPut);
            output = mPut.getResponseBodyAsString( );

            mPut.releaseConnection( );
            System.out.println("satus : " + satus);
            System.out.println("output : " + output);
        }catch(Exception e){
             System.out.println("Exception in creating node in neo4j : " + e);
        }

    }

    private String toJsonNameValuePairCollection(String name, String value) {
        return String.format("{ "%s" : "%s" }", name, value);
    }

Querying the database

Now the final piece of puzzle, we have all the data in the database and now we wan’t to query the database.  Neo4J uses Graph traversal algorithms to query the database. Lets check how to do that.

  1. The traversal is done by invoking following url                                                           <start-node-url>/traverse/node for example http://localhost:7474/db/data/node/1/traverse/node
  2. This is a POST rest web service.
  3. It receives and send json data.
  4. Once the request completes we get back array of nodes in json format.

To get the traversal work we first need to create two custom classes which will generate the json payload to be sent, they are TraversalDescription and Relationship. Please don’t confuse them with the interfaces defined in core neo4j code base. They can be found in example code here. http://grepcode.com/snapshot/repo1.maven.org/maven2/org.neo4j.examples/neo4j-server-examples/1.9.M04/ 

For your benefit I will paste these classes right here. 

Relationship.java

package com.aranin.spring.neo4j;

/**
 * Created by IntelliJ IDEA.
 * User: Niraj Singh
 * Date: 7/22/13
 * Time: 10:49 AM
 * To change this template use File | Settings | File Templates.
 */
public class Relationship {

    public static final String OUT = "out";
    public static final String IN = "in";
    public static final String BOTH = "both";
    private String type;
    private String direction;

    public String toJsonCollection() {
        StringBuilder sb = new StringBuilder();
        sb.append("{ ");
        sb.append(" "type" : "" + type + """);
        if(direction != null) {
            sb.append(", "direction" : "" + direction + """);
        }
        sb.append(" }");
        return sb.toString();
    }

    public Relationship(String type, String direction) {
        setType(type);
        setDirection(direction);
    }

    public Relationship(String type) {
        this(type, null);
    }

    public void setType(String type) {
        this.type = type;
    }

    public void setDirection(String direction) {
    }
}

TraversalDescription.java

package com.aranin.spring.neo4j;

/**
 * Created by IntelliJ IDEA.
 * User: Niraj Singh
 * Date: 7/20/13
 * Time: 9:18 PM
 * To change this template use File | Settings | File Templates.
 */

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class TraversalDescription {

    public static final String DEPTH_FIRST = "depth first";
    public static final String NODE = "node";
    public static final String ALL = "all";

    private String uniqueness = NODE;
    private int maxDepth = 1;
    private String returnFilter = ALL;
    private String order = DEPTH_FIRST;
    private List<Relationship> relationships = new ArrayList<Relationship>();

    public void setOrder(String order) {
        this.order = order;
    }

    public void setUniqueness(String uniqueness) {
        this.uniqueness = uniqueness;
    }

    public void setMaxDepth(int maxDepth) {
        this.maxDepth = maxDepth;
    }

    public void setReturnFilter(String returnFilter) {
        this.returnFilter = returnFilter;
    }

    public void setRelationships(Relationship... relationships) {
        this.relationships =  Arrays.asList(relationships);
    }

    public String toJson() {
        StringBuilder sb = new StringBuilder();
        sb.append("{ ");
        sb.append(" "order" : "" + order + """);
        sb.append(", ");
        sb.append(" "uniqueness" : "" + uniqueness + """);
        sb.append(", ");
        if (relationships.size() > 0) {
            sb.append(""relationships" : [");
            for (int i = 0; i < relationships.size(); i++) {
                sb.append(relationships.get(i).toJsonCollection());
                if (i < relationships.size() - 1) { // Miss off the final comma
                    sb.append(", ");
                }
            }
            sb.append("], ");
        }
        sb.append(""return filter" : { ");
        sb.append(""language" : "builtin", ");
        sb.append(""name" : "");
        sb.append(returnFilter);
        sb.append("" }, ");
        sb.append(""max depth" : ");
        sb.append(maxDepth);
        sb.append(" }");
        return sb.toString();
    }
}

Now with this in place lets check how to query the neo4jdb. We will create a searchDatabase method for that.

public String searchDatabase(String nodeURI, String relationShip){
        String output = null;

        try{

            TraversalDescription t = new TraversalDescription();
            t.setOrder( TraversalDescription.DEPTH_FIRST );
            t.setUniqueness( TraversalDescription.NODE );
            t.setMaxDepth( 10 );
            t.setReturnFilter( TraversalDescription.ALL );
            t.setRelationships( new Relationship( relationShip, Relationship.OUT ) );

            System.out.println(t.toString());
            HttpClient client = new HttpClient();
            PostMethod mPost = new PostMethod(nodeURI+"/traverse/node");

            /**
             * set headers
             */
            Header mtHeader = new Header();
            mtHeader.setName("content-type");
            mtHeader.setValue("application/json");
            mtHeader.setName("accept");
            mtHeader.setValue("application/json");
            mPost.addRequestHeader(mtHeader);

            /**
             * set json payload
             */
            StringRequestEntity requestEntity = new StringRequestEntity(t.toJson(),
                                                                        "application/json",
                                                                        "UTF-8");
            mPost.setRequestEntity(requestEntity);
            int satus = client.executeMethod(mPost);
            output = mPost.getResponseBodyAsString( );
            mPost.releaseConnection( );
            System.out.println("satus : " + satus);
            System.out.println("output : " + output);
        }catch(Exception e){
 System.out.println("Exception in creating node in neo4j : " + e);
        }

        return output;
    }

Experience the power of neo4j

Now that we have all the methods in place for creating node, adding property to node, adding relationship, adding properties to relationship and querying the database. Let create a program that will perform all these activities. We will create a main method in following way.

Relationship relationship;
    final String SERVER_ROOT_URI = "http://localhost:7474";

    private static enum RelTypes implements RelationshipType
    {
        KNOWS,friend;
    }

    public static void main(String[] args){
        Neo4jHello neo4jHello = new Neo4jHello();

        /**
         * check if server is running
         */
        int status = neo4jHello.getServerStatus();

        System.out.println("neo4j server status : " + status);

        /**
         * create a node
        */

        String firstNodeLocation = neo4jHello.createNode();

        String secondNodeLocation = neo4jHello.createNode();

        /**
         * add properties to node
         */

        //neo4jHello.addProperty("http://localhost:7474/db/data/node/1", "name" , "Niraj");
        //neo4jHello.addProperty("http://localhost:7474/db/data/node/2", "name" , "Manisha");

        neo4jHello.addProperty(firstNodeLocation, "name" , "Niraj");
        neo4jHello.addProperty(secondNodeLocation, "name" , "Manisha");

        /**
         *  add relationship between nodes
         */
        String relationAttributes = "{ "married" : "yes","since" : "2005" }";
        String relationShipURI = neo4jHello.addRelationship("http://localhost:7474/db/data/node/1",
                                                            "http://localhost:7474/db/data/node/2",
                                                            "friend",
                                                            relationAttributes);

        /**
         * add properties to relationship
         */

         neo4jHello.addPropertyToRelation(relationShipURI, "weight", "5");

        /**
         * finally traverse all the nodes starting from node 1
         */

        neo4jHello.searchDatabase(firstNodeLocation, "friend");

    }

References

  1. http://www.neo4j.org/learn
  2. http://grepcode.com/snapshot/repo1.maven.org/maven2/org.neo4j.examples/neo4j-server-examples/1.9.M04/
  3. http://en.wikipedia.org/wiki/Neo4j
  4. http://www.javaworld.com/javaworld/jw-02-2013/130204-how-neo4j-beat-oracle-db.html
  5. https://github.com/neo4j
  6. http://java.dzone.com/articles/10-caveats-neo4j-users-should

That is all folks. Hope you enjoyed this post and found it useful. Don’t forget to drop a comment or two to keep me encouraged.

Warm Regards

Niraj

Print Friendly

About Niraj Singh

I am CEO and CoFounder of a startup "Aranin Software Private Limited, Bangalore. I completed my graduation in 2002 as an Aerospace Engineer from IIT Kharagpur. I love working on new ideas and projects and recently released my first open source project JaiomServer "http://jaiomserver.org". I have 9 years of experience in IT industries most of which I have spent in developing community applications for various clients using java. Some of the sites in which I have actively involved with are hgtv.com, food.com, foodnetwork.com, pickle.com, diynetwork.com etc.
This entry was posted in Graph Database, neo4j and tagged , . Bookmark the permalink.

7 Responses to Java Tutorial on Neo4j – A Next Generation Graph Database

  1. J Wang says:

    Great tutorial! It really helped me out.

  2. Andy says:

    Wonderful tutorial. Keep up the good work..

  3. kiran says:

    I means repetitive used operational patterns

    • Niraj Singh says:

      Hi Kiran,
      Can you explain your question a bit. If I understand properly you need a log analyzer like Sumologic or even Newrelic.

      Neo4j as it stands is a graph database. It deals with relationships between entities which can be mapped as graph. The graph can then be traversed using various algorithms. It is great for simulating and analyzing networks.

      Just for argument sake let us try solving your problem. Assume that each operation is a vertex. So now the operations are called by different operations to perform a task. A call represents the vertex in the graph. I am assuming that this information is present in your log and you can read it. For example

      Task 1- Operation A calls B calls C.
      Task 2 – D calls E calls A and so forth.

      Steps.
      1. Create a list of all the task.
      2. For each task create a stack and push it to the list. So your datastructure is List
      3. For each of the operation create a Neo4j node.
      4. Now using the call list add relationship between nodes.
      5. Node with maximum number of relationship is your most repeated operation.

      Hope I have not made a complete fool of myself :-) .