Beginning with Neo4j and Neo4jClient

4. January 2013 18:07 by Cameron in   //  Tags: , , , , , , , , ,   //   Comments

I will try my best to include everything necessary to get started with Neo4j. This is not meant to be a guide on how to program with C#, Visual Basic, Java, Cypher, or Gremlin. You will need to either have prior experience with those languages or read other resources to learn about them. If you don’t understand some of the computer science jargon, please let me know and I will try and make the wording more clear.

I'm not going to go into too much graph theory in this tutorial. You should have a basic understanding of what a directed graph is and how to create a data model since you seem to be interested in graph databases. All that you really need to know about graph theory is that a graph is a set of related nodes representing entities with relationships connecting the nodes.

Graph databases are an excellent way to model social data compared traditional relational databases. Social networking websites such as Twitter and Facebook use graph dbs for quickly querying through millions of users and their relationships to other objects or users. It would be much slower to use an RDBMS for a website like Facebook because of the need to select from tables with millions of records and perform joins on those tables. Joins are expensive operations in SQL databases and graph databases don't require explicit joins due to the nature of a graph's structure.

About Tools

Java is a programming language that runs in a virtual environment allowing it to run on thousands of different devices that have a Java virtual machine. Neo4j is an enterprise level graph database written in Java. Neo4jClient is a .NET client for interfacing with Neo4j’s REST API.

About Neo4jClient

Neo4jClient serializes  and deserializes objects to and from JSON to interact with the server which makes it very easy to store and retrieve objects.

Installation

Java

I’m assuming you already have Java installed, but if you don’t, you will need the JRE for Windows installed in order to run Neo4j. You can download the JRE from Oracle. When downloading the JRE, you can choose either the standalone JRE or the JDK, which includes the JRE. The JDK is mainly for Java developers and is not required if you don’t do Java development. Also, about whether to choose x86 or x64, I’d recommend that you choose x86 for simplicity. Most likely, you won’t need 64-bit addressing with your Java installation. This would only be if you have another project that requires the x64 release. The easiest download is any of the .exe installers as it will guide you through the installation process. Installation should take about 5 minutes and then you’ll be ready to move to setting up Neo4j.

Neo4j

Next, you should download Neo4j from neo4j.org. Unless you want to be bleeding edge, it’s recommended to download the Major Stable Community Version. At the time of writing, this is version 1.8.1. Make sure to get the Windows specific download. Follow the directions on the download page and open up a command prompt with administrator privileges to start your newly installed Neo4j server. Once you have started the server, you can browse to your web admin interface at http://localhost:7474. From there, you can use the Data browser page to create nodes and relationships. In the console tab, you can query your database using Cypher or traverse the graph using Gremlin. You can even send HTTP requests to the REST API if you want to learn about how to talk to Neo4j from other tools. In the Indexes tab, you can create indexes for fast retrieval of nodes or relationships. I will talk more about indexes later. You are now ready to setup Neo4jClient.

Visual Studio and Neo4jClient

You need to have Visual Studio 2010 Professional or higher or Visual C# 2012 Express Edition (free) installed to be able to install Neo4jClient using the Nuget package manager.  Unfortunately, Nuget does not work with Visual C# 2010 Express Edition. 

Create a new Visual C# or Visual Basic project and then proceed to installing Neo4jClient. You can install Neo4jClient by managing Nuget packages on your project or by running the following command in the Package Manager Console:

Install-Package Neo4jClient

Brief Overview of Neo4j and Neo4jClient

Indexes

Indexes are created for fast retrieval of information at a later point. This is extremely useful when querying a graph database on the order of millions of nodes. Manual traversal is slower and less efficient. One of the advantages of graph databases is speed and it is important to utilize indexes to increase speed.

Full text vs. Exact

A full text index is for searching on a node’s properties text, allowing partial or complete text to be searched. For example, if you have a set of nodes representing the Star Wars movies, if you search for nodes in the Movie index with a name like “Star Wars” with a full text index, you will get all nodes containing the text “Star Wars” in the name property.

However, an exact index requires that you search on a node’s properties text with exact text. For example, if you have a set of nodes representing the Star Wars movies, if you search for just the text “Star Wars” in an exact index, it will not return anything because there are no nodes with just the text “Star Wars”

Relationship Properties

In addition to adding properties to nodes, relationships can also have properties. This can be helpful if you are trying to better describe a relationship. If you want a more complex data model, you can add a payload class to your relationship class to store properties on your relationship. This is often referred to as attributes of a relationship in graph theory.

For example, you could add a property called “comment” to the Directed relationship to add extra information about the direction of a movie from a director. This would improve the data model to provide more information about movies as a whole.

Sample Database Setup

Once Neo4jClient is installed, you can setup a sample database by using the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Neo4jClient;
using Neo4jClient_Tutorial.Models;
using Neo4jClient_Tutorial.Models.Relationships;

namespace Neo4jClient_Tutorial.DAL
{
    /// <summary>
    /// Class to provide sample data for the graph
    /// </summary>
    public class Scaffolding
    {
        GraphClient client;

        public Scaffolding()
        {
            client = new GraphClient(new Uri("http://localhost:7474/db/data"));

            client.Connect();

            CreateNodesRelationshipsIndexes();  
        }

        private void CreateNodesRelationshipsIndexes()
        {
            // Create Indexes
            client.CreateIndex("Movie", new IndexConfiguration() { Provider = IndexProvider.lucene, Type = IndexType.fulltext }, IndexFor.Node); // full text node index
            client.CreateIndex("Director", new IndexConfiguration() { Provider = IndexProvider.lucene, Type = IndexType.exact }, IndexFor.Node); // exact node index
            client.CreateIndex("Genre", new IndexConfiguration() { Provider = IndexProvider.lucene, Type = IndexType.fulltext }, IndexFor.Node); // full text node index

            // Create Entities
            // Movies
            Movie swI = new Movie() { Name = "Star Wars: Episode I - The Phantom Menace", Description = "Begins the story of Anakin Skywalker" };

            var starWarsEpisodeI = client.Create(swI,
                new IRelationshipAllowingParticipantNode<Movie>[0],
                new []
                {
                    new IndexEntry("Movie")
                    {
                        { "Name", swI.Name },
                        { "Description", swI.Description },
                        { "Id", swI.Id.ToString() }
                    }
                });

            Movie swIV = new Movie() { Name = "Star Wars: Episode IV - A New Hope", Description = "First Starwars movie to debut on the big screen" };

            var starWarsEpisodeIV = client.Create(swIV,
                new IRelationshipAllowingParticipantNode<Movie>[0],
                new []
                {
                    new IndexEntry("Movie")
                    {
                        { "Name", swIV.Name },
                        { "Description", swIV.Description },
                        { "Id", swIV.Id.ToString() }
                    }
                });

            Movie indy = new Movie() { Name = "Indiana Jones and the Temple of Doom", Description = "Second movie in the original Indiana Jones trilogy" };

            var indianaJonesTempleOfDoom = client.Create(indy,
                new IRelationshipAllowingParticipantNode<Movie>[0],
                new[]
                {
                    new IndexEntry("Movie")
                    {
                        { "Name", indy.Name },
                        { "Description", indy.Description },
                        { "Id", indy.Id.ToString() }
                    }
                });

            Movie jp = new Movie() { Name = "Jurassic Park", Description = "First Jurassic park movie" };

            var jurassicPark = client.Create(jp,
                new IRelationshipAllowingParticipantNode<Movie>[0],
                new[]
                {
                    new IndexEntry("Movie")
                    {
                        { "Name", jp.Name },
                        { "Description", jp.Description },
                        { "Id", jp.Id.ToString() }
                    }
                });

            Movie et = new Movie() { Name = "ET", Description = "ET phone home" };

            var ET = client.Create(et,
                new IRelationshipAllowingParticipantNode<Movie>[0],
                new[]
                {
                    new IndexEntry("Movie")
                    {
                        { "Name", et.Name },
                        { "Description", et.Description },
                        { "Id", et.Id.ToString() }
                    }
                });

            // Directors

            Director lucas = new Director() { Name = "George Lucas" };

            var georgeLucas = client.Create(lucas,
                new IRelationshipAllowingParticipantNode<Director>[0],
                new[]
                {
                    new IndexEntry("Director")
                    {
                        { "Name", lucas.Name },
                        { "Id", lucas.Id.ToString() }
                    }
                });

            Director spielberg = new Director() { Name = "Steven Spielberg" };

            var stevenSpielberg = client.Create(spielberg,
                new IRelationshipAllowingParticipantNode<Director>[0],
                new[]
                {
                    new IndexEntry("Director")
                    {
                        { "Name", spielberg.Name },
                        { "Id", spielberg.Id.ToString() }
                    }
                });

            // Genres
            Genre sf = new Genre() { Name = "Science Fiction" };

            var sciFi = client.Create(sf,
                new IRelationshipAllowingParticipantNode<Genre>[0],
                new[]
                {
                    new IndexEntry("Genre")
                    {
                        { "Name", sf.Name },
                        { "Id", sf.Id.ToString() }
                    }
                });

            Genre adv = new Genre() { Name = "Adventure" };

            var adventure = client.Create(adv,
                new IRelationshipAllowingParticipantNode<Genre>[0],
                new[]
                {
                    new IndexEntry("Genre")
                    {
                        { "Name", adv.Name },
                        { "Id", adv.Id.ToString() }
                    }
                });

            // Create Relationships
            client.CreateRelationship(starWarsEpisodeI, new PartOf(sciFi));
            client.CreateRelationship(starWarsEpisodeIV, new PartOf(sciFi));

            client.CreateRelationship(indianaJonesTempleOfDoom, new PartOf(adventure));
            
            client.CreateRelationship(jurassicPark, new PartOf(sciFi));
            client.CreateRelationship(jurassicPark, new PartOf(adventure));

            client.CreateRelationship(ET, new PartOf(sciFi));

            client.CreateRelationship(georgeLucas, new Directed(starWarsEpisodeI, new Models.Payloads.Payload() { Comment = "George Lucas' second Star Wars trilogy" }));
            client.CreateRelationship(georgeLucas, new Directed(starWarsEpisodeIV, new Models.Payloads.Payload() { Comment = "First Starwars movie that George Lucas directed" }));                             client.CreateRelationship(stevenSpielberg, new Directed(indianaJonesTempleOfDoom, new Models.Payloads.Payload() { Comment = "Lucas wrote the story while Spielberg directed" }));
            client.CreateRelationship(stevenSpielberg, new Directed(jurassicPark, new Models.Payloads.Payload() { Comment = "Huge box office success" }));
            client.CreateRelationship(stevenSpielberg, new Directed(ET, new Models.Payloads.Payload() { Comment = "One of Spielberg's most successful movies" }));
        }
    }
}

I've attached a sample ASP.NET MVC 4 project for Visual Studio 2012, but you should be able to get it working in Visual Studio 2010 by importing the code without any issues. It includes all entity, relationship, and payload models. I added a few basic views for visualizing the data. Feel free to fill out the method stubs to create views to view the rest of the entities. I will look at creating another tutorial building on this project for adding/deleting/updating items from the database. I've also attached an image of the final graph. It should be easy to determine which nodes are what type of entity based on the relationship definitions. Please let me know if you have questions in the comments below.

Neo4jClient Tutorial.zip (12.48 mb)

blog comments powered by Disqus

Month List

Tag cloud