Embedding Neo4j to Android

post2

We all have been eagerly awaiting to run Neo4j on mobile devices, specially on Android. Finally it’s here. During the Android Hacking at Google I/O an amazing new Community project was announced: Neo4j Mobile for Android v0.1!The project is currently available on GitHub for experimentation and evaluation purposes. As the version 0.1 indicates that it is currently an incubation project, the project itself is fully-functional, but as-yet unsupported. We will be developing a small use-case to get ourselves acquainted with it.

How does it work?

Android has a notion of Services, which can be assumed to be as background processes. Neo4j Mobile for Android runs as a service, and is accessed via Android Inter-Process Communication using an AIDL (Android Interface Definition Language) connector. This makes it possible for multiple apps on an Android device to access the same database service. The picture below summarizes an example application architecture, taken from the original project, showing Neo4j Mobile for Android interacting with other solution elements:

Neo4j concept V1_0

The Neo4j project has a pretty modular structure. It basically consists of 4 modules, while the other modules have been omitted because they are much  more oriented towards server usage, REST and command-line invocations, all of which do not apply to this particular use-case.

  • neo4j-kernel : Core graph DB concepts, embeddable database, I/O, transactions, …
  • neo4j-graph-algo : Standard graph algorithms,
  • neo4j-graph-matching : Graph matching algorithms,
  • neo4j-lucene-indexing : Indexing support via Apache Lucene.

Embedding Neo4j

There are two ways to embedded Neo4j in your application:

  1. Reference the neo4j-android project as an Android library project, or
  2. Copy the neo4j-android JARs after building the project and use it like we have been doing with any other external Java library.

Building the Project

The Noe4J APK has been successfully built with Java 1.6, Ant 1.8.1, Android SDK r21 and tested on Android 4.0.3.

There’s a rudimentary demo app which is included in the project. We are going to build the project and install the app on our emulator/device.

  • First, you need to have Android SDK setup with Eclipse. Refer android developer site for details.
  • Get the source from here.
  • You need to create local.properties file in each project, which should point to the location of the Android SDK.
sdk.dir=C:\\Android\\android-sdk
  • Build and install the service
cd neo4j-android-service
ant clean debug
adb uninstall org.neo4j.android.service
adb install bin/neo4j-android-service-debug.apk
  • Build and install the dbinspector app
cd neo4j-android-dbinspector
ant clean debug
adb uninstall com.noser.neo4j.android.dbinspector
adb install bin/neo4j-android-dbinspector-debug.apk
  • Run the dbinspector app on the target device. The service will be started automatically.

DB_Inspector_app

NOTE: You might face a lot of errors while building the service and demo app. The problem basically arises due to the different version of build.xml present in neo4j-android project folder and the one in the android-sdk/tools/ant/ folder. The build error on the active terminal will display the lines where the discrepancy is present. Compare both the build.xml files and edit the one present in the neo4j-android folder to build the project successfully.

Go through the project page to gain in-depth knowledge of the implementation.


It’s now time to include Neo4j in our own use-case. As mentioned earlier, we will be referencing neo4j-android.jar as an external Java library, along with neo4j-android-client.jar and neo4j-android-common.jar. But before we begin working on our use-case, it’s advised to go through the DB-Inspector app code to better understand the API and the resources used.

Our aim here is to create a database, create some nodes and establish relationship between them. Once all done, we will be generating a log to verify it all went well.

After setting up your development environment on Eclipse, create a new Android Application Project. Keep the Target SDK version as 15.

new_proj

Eclipse automatically creates various folders inside your project. One of them is ‘Libs’ where you place your external libraries that you want to include in your build path. Copy neo4j-android.jar from neo4j-android\binneo4j-android-client.jar  from neo4j-android-client\bin and neo4j-android-common.jar from neo4j-android-common\bin  to Libs of your newly created android project.

The ‘Libs’ folder of your project will already be containing android-support-v4.jar.

Refresh your project to view newly added JARs in the Libs folder. Select them, right click, goto Build Path >> Add to Build Path. The JARs would be removed from the Libs folder and added to Referenced Libraries folder.

As explained earlier, Neo4j Mobile for Android runs as a service, and is accessed via Android Inter-Process Communication using an AIDL (Android Interface Definition Language) connector. AIDL allows you to define the programming interface that both the client and service agree upon in order to communicate with each other using interprocess communication (IPC). The Neo4j service interface has already been implemented, we now have to override onBind() to return the implementation of the Stub class.

Now we are all set to code. Open MyActivity.java and add the highlighted imports as below.

package com.bishwajeet.myneo4japp;

import org.neo4j.android.common.IGraphDatabase;
import org.neo4j.android.common.INeo4jService;
import org.neo4j.android.client.Neo4jService;

import android.os.Bundle;
import android.os.IBinder;

If the imports do not show any error it means you have successfully included the JARs in your build path.

Declare instances of INeo4jService and IGraphDatabase as below.

public class MainActivity extends Activity {

	private INeo4jService neoServiceManager;
	private IGraphDatabase graphDB;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

Our client application can bind to Neo4j Service by calling bindService(). When it does, it must provide an implementation of ServiceConnection, which monitors the connection with the service. The bindService() method returns immediately without a value, but when Android system creates the connection between the client and the service, it calls onServiceConnected() on the service connection, to deliver the IBinder that the client can use to communicate with the service. Create the ServiceConnection as given below.

private ServiceConnection neoServiceConnection = new ServiceConnection() {

	@Override
	public void onServiceDisconnected(ComponentName name) {
		// TODO Auto-generated method stub

	}

	@Override
	public void onServiceConnected(ComponentName name, IBinder service) {
		// TODO Auto-generated method stub

	}
};

We will get back to what has to be done within the above two methods.

Since a service connection has been created, we can now bind our Neo4j service with our app inside the onCreate() method.

boolean neoConnect = Neo4jService.bindService(getApplicationContext(), neoServiceConnection);

Pass the application context as the first parameter and the service connection as second. If the connection is successfully established, it will return a boolean as true. Once done, fill the onServiceConnected as below. Leave the onServiceDisconnected() empty as of now.

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
	neoServiceManager = INeo4jService.Stub.asInterface(service);
}

I will be utilizing the Options Menu for creating a simple UI for our app. Design the options menu to have options for creating a graph database, creating nodes, creating relationships and firing cypher query. Go through the reference for creating an Android Options Menu. Note that you can create any UI depending upon your requirement.

I have created four menu items in the options menu. We will look each of the one-by-one.

Creating Database Instance

Before we create our database instance, we need to insure a database of the same name does not already exists. Refer below code.

@Override
public boolean onOptionsItemSelected(MenuItem item)	{
	parceableError = new ParcelableError();
	switch (item.getItemId())	{
			case 	R.id.create_db:
				try {
					if(!neoServiceManager.databaseExists("MyNewGraphDatabase"))	{
							graphDB = neoServiceManager.openOrCreateDatabase("MyNewGraphDatabase", new ParcelableError());

						if(graphDB != null)	{
							logText.append("\nGraph DB created : MyNewGraphDatabase");
						}
						else	{
							logText.append("\nError in creating database!");
						}
					}
					else	{
						logText.append("\nDatabase already exists!");
					}
				}
				catch (RemoteException e)	{
					Log.e("RemoteException", e.toString());
					e.getMessage();
				}
				break;

Creating Nodes

We will be creating a total of four nodes, representing a Country, a State of that country and two cities of the State. The createNode() method has a return type Long, which will help us in referencing the node while creating relationships. Set property key-value pair according to your need.

case	R.id.create_node:
	try {
		if (neoServiceManager.databaseExists("MyNewGraphDatabase")) {
			logText.append("\nChecking database existence.");

			if(neoServiceManager.isDatabaseOpen("MyNewGraphDatabase")) {
				logText.append("\nDatabase is open.");
				logText.append("\nCreating Node...");

				graphDB.beginTx(parceableError);
				try {
					nodeCountry = new ParcelableNode();
					nodeState = new ParcelableNode();
					nodeCityOne = new ParcelableNode();
					nodeCityTwo = new ParcelableNode();

					nodeCountry.setProperty("Name", "India");
					nodeState.setProperty("Name", "Maharashtra");
					nodeCityOne.setProperty("Name", "Mumbai");
					nodeCityTwo.setProperty("Name", "Pune");

					nodeCountryID = graphDB.createNode(nodeCountry, parceableError);
					nodeStateID = graphDB.createNode(nodeState, parceableError);
					nodeCityOneID = graphDB.createNode(nodeCityOne, parceableError);
					nodeCityTwoID = graphDB.createNode(nodeCityTwo, parceableError);

					logText.append("\nCreated Country node : '"+nodeCountry+"' with nodeID '"+nodeCountry+"'.");
					logText.append("\nCreated State node : '"+nodeState+"' with nodeID '"+nodeStateID+"'.");
					logText.append("\nCreated City nodes : '"+nodeCityOne+"' with nodeID '"+nodeCityOneID+"', '"+nodeCityTwo+"' with nodeID '"+nodeCityTwoID+"'");

					graphDB.txSuccess(parceableError);
				} finally {
					graphDB.txFinish(parceableError);
				}
			}
		}
		else {
			logText.append("\nDatabase does not exist!");
		}
	} catch (RemoteException e) {
		Log.e("RemoteException", e.toString());
		e.getMessage();
	}
break;

Creating Relationships

We have created our nodes and have their corresponding nodeIDs. We will now establish relationships between them.

case 	R.id.create_rel:
	try {
		graphDB.beginTx(parceableError);

		try {
			relateCountryState = new ParcelableRelationship();
			relateCountryState.setStartNodeId(nodeCountryID);
			relateCountryState.setEndNodeId(nodeStateID);
			relateCountryState.setName("HAS");
			relateCountryStateID = graphDB.createRelationship(relateCountryState, parceableError);
			logText.append("\nCreated Country -> State relationship with RelationshipID: '"+relateCountryStateID+"'");

			relateStateCity = new ParcelableRelationship();
			relateStateCity.setStartNodeId(nodeStateID);
			relateStateCity.setEndNodeId(nodeCityOneID);
			relateStateCity.setEndNodeId(nodeCityTwoID);
			relateStateCity.setName("HAS");
			relateStateCityID = graphDB.createRelationship(relateStateCity, parceableError);
			logText.append("\nCreated State -> City relationship with RelationshipID: '"+relateStateCityID+"'");

			relateCountryCity = new ParcelableRelationship();
			relateCountryCity.setStartNodeId(nodeCountryID);
			relateCountryCity.setEndNodeId(nodeCityOneID);
			relateCountryCity.setEndNodeId(nodeCityTwoID);
			relateCountryCity.setName("HAS");
			relateCountryCityID = graphDB.createRelationship(relateCountryCity, parceableError);
			logText.append("\nCreated Country -> City relationship with RelationshipID: '"+relateCountryCityID+"'");

			graphDB.txSuccess(parceableError);
		} finally {
			graphDB.txFinish(parceableError);
		}
	} catch  (RemoteException e) {
		Log.e("RemoteException", e.toString());
		e.getMessage();
	}
break;

Deleting Database

Finally, we will be erasing the database and conclude the onOptionsItemSelected() method.

		case	R.id.delete_db:
				try {
					graphDB.beginTx(parceableError);

					try {
						boolean flag = neoServiceManager.deleteDatabase("MyNewGraphDatabase", new ParcelableError());
						if(flag)
							logText.append("\nDatabase Erased.");

						graphDB.txSuccess(parceableError);
					} finally {
						graphDB.txFinish(parceableError);
					}
				} catch (RemoteException e) {
					Log.e("RemoteException", e.toString());
					e.getMessage();
				}
				break;
		default:
			Toast.makeText(getApplicationContext(), "Welcome to Neo4j Android App!", Toast.LENGTH_LONG).show();
	}
	return super.onOptionsItemSelected(item);
}

Add the following declarations before the start of onCreate() method.

private INeo4jService neoServiceManager;
private IGraphDatabase graphDB;
private ParcelableError parceableError;
private ParcelableNode nodeCountry, nodeState, nodeCityOne, nodeCityTwo;
private ParcelableRelationship relateCountryCity, relateStateCity, relateCountryState;
private TextView logText;
private long nodeCountryID, nodeStateID, nodeCityOneID, nodeCityTwoID, relateCountryCityID, relateStateCityID, relateCountryStateID;

Your MyActivity.java page is complete now. We need to provide READ, WRITE & ADMIN permission in the AndroidManifest.xml file. Add the below lines in the manifest file.

<uses-permission android:name="org.neo4j.android.permission.READ"/>
<uses-permission android:name="org.neo4j.android.permission.WRITE"/>
<uses-permission android:name="org.neo4j.android.permission.ADMIN"/>

Building the Project

As we have done with the DBInspector App, we will be doing an Ant build of our project. But before that we must create the build.xml file for the Ant build.

<?xml version="1.0" encoding="UTF-8"?>
<project name="MyNeo4jApp" default="help">

    <property file="local.properties" />
    <property file="ant.properties" />
    <property environment="env" />
    <condition property="sdk.dir" value="${env.ANDROID_HOME}">
        <isset property="env.ANDROID_HOME" />
    </condition>
    <loadproperties srcFile="project.properties" />
    <fail
            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
            unless="sdk.dir"
    />
    <import file="custom_rules.xml" optional="true" />
    <import file="${sdk.dir}/tools/ant/build.xml" />
</project>

Now do an Ant build of the project.

cd MyNeo4jApp
ant clean debug
adb install bin/MyNeo4jApp-debug.apk

Install the Neo4j service on your device first, followed by the MyNeo4jApp we just created. Test each of the options and analyze the messages logged onto the app screen. It should be like the one below.

Screenshot_2014-08-11-00-00-40

I hope this tutorial has been informative.

Now go and play with it!! 🙂

 

Integrating Facebook C# SDK & Neo4J

Force-Directed Graph

Hello Everyone!! This is my first tutorial and it’s going to be a long one. Bear with me on this because once you’re done with it you would be familiar with various concepts related to totally different platforms, namely, Facebook SDK, ASP.Net with C# and Neo4J Graph DB. Before getting started let us go through the use-case and how are we going to achieve it. Our objective today is to retrieve a logged-in user’s data from Facebook using Facebook SDK for .Net, prepare the retrieved data for storing it in Neo4J Graph DB and then finally visualize that data graphically.

So much for the brief introduction, let’s get down to business. First of all you need to have Visual Studio 2010 or higher installed on your system. You will also need to have Neo4J setup on your system. The download page contains multiple options, go for community version with stable release, i.e. Ne04J 2.0.3. The website contains detailed instructions and tutorials for understanding the basic concepts of graph database. Neo4J uses a special query language, called Cypher . Cypher is a declarative graph query language that allows for expressive and efficient querying and updating of the graph store. Cypher is a relatively simple but still very powerful language. Very complicated database queries can easily be expressed through Cypher. This link provides a detailed explanation and features of Cypher.

Creating a Facebook Application

Before we begin using the Facebook SDK for .NET we must create a Facebook application. To do so navigate to http://developers.facebook.com/apps and click the ‘Create New App’ button. Follow the steps to create an app and note down your AppId for future use.

Installation

Facebook does not provide its own SDK for .NET but allows a third-party SDK for C#. You can find it here. The best way for getting started with Facebook SDK for .NET is to install it using NuGet. You can download it from nuget.org. Use the latest version because the features used in the Facebook SDK for .NET will not work with older versions of NuGet. The NuGet website contains detailed instructions on how to integrate it with Visual Studio. Note: It requires VS 2010 or higher.

Managing Facebook NuGet Package

Create a new ASP.NET Empty Web Site. Name it something appropriate. To add the package to your project right click on the reference folder and select ‘Manage Nuget Packages…’. Search for the package titled ‘Facebook’, select & install it. manage_nuget_packages

Configuring Facebook SDK for .NET

The only setting we need to change is the ‘Site URL’ under the ‘Website’ settings. The Site URL must match the URL you are using for local development. Set this URL to http://localhost:#### where #### is the port you are using for local development. NOTE: There is a bug in the Facebook JavaScript SDK that prevents you from performing logins when running on non-standard ports on localhost in Internet Explorer. You must either use port 80 or test this in a browser other than Internet Explorer.

Making Your First Request

Facebook SDK for .NET makes it very easy to retrieve data from Facebook Graph API. Create a new WebForm inside your website. Let it be called Default.aspx. Open Default.aspx.cs, include the reference by adding

using Facebook;

The following code shows how to call Graph API to retrieve Bishwajeet Kumar’s public information.

var client = new FacebookClient();
dynamic me = client.Get("msg.bishwajeet.kumar");

The result returned by the Get() method is a dynamic object which contains properties like first_name, last_name, user name, id, link, gender, etc. You can view the result of this request by navigating to http://graph.facebook.com/msg.bishwajeet.kumar in your browser. The JSON output is given below.

{
   id: "100000735276467",
   first_name: "Bishwajeet",
   gender: "male",
   last_name: "Kumar",
   link: "https://www.facebook.com/msg.bishwajeet.kumar",
   locale: "en_US",
   name: "Bishwajeet Kumar",
   username: "msg.bishwajeet.kumar"
}

C#’s dynamic objects come really handy in this scenario.

dynamic me = client.Get("msg.bishwajeet.kumar");
string firstName = me.first_name;
string lastName = me.last_name;

I have used C# dynamic object in the above code. A dynamic object is an object that is evaluated only at run-time. It can be actually assumed to be a Dictionary<string, object>.

Accessing User Information

Its time to do something interesting now. We already saw how to make a request for public information using Facebook SDK for .NET. Not all the information of the user is made public. In order to access any information that is not public such as user’s likes, profile details, friend list, or Time Line posts we need to provide a valid access token when making the request.

Obtaining an Access Token

For the purpose of security, Facebook provides Access Tokens for uniquely identifying users. The Access Token changes dynamically every hour, or so. We are going to start by obtaining an access token from Facebook’s Graph API tool. You can easily find the tool at https://developers.facebook.com/tools/accesstoken/.

Retrieving User Data

Since we have obtained an access token, we can make request for user’s private data. Do keep in mind that since we did not request any special permission, we will not be able to access most of the user’s data. We will be discussing about the special permissions later.

var accessToken = "place your access token here";
var client = new FacebookClient(accessToken);
dynamic me = client.Get("me");
string myDetails = me.about;

Note: “me” is a special variable that indicates that we are making the request in the context of the user who’s access token was provided in the above request.

We will be using the above technique for all kinds of requests, such as, friend lists, likes, Timeline posts and many more. However, the type of data you wish to request from the user depends upon the type of permission you have requested from the user. For further details regarding permissions, feel free to browse https://developers.facebook.com/docs/facebook-login/permissions/v2.0#permissions.

Obtaining Access Token from Facebook

As already discussed, Facebook does not discloses user’s credentials, instead it allows you to obtain access tokens for the user to access your application. The access token includes the type of permission you have the request from the user.

In order to obtain an access token from the user, we must present them with an authentication dialog. This dialog varies depending on the device for which your application is built. Regardless of the device choices we are actually presenting the user with a Facebook login page.

Requesting an Access Token from a Website

In order to get an access token from your users on a website you must use the either the Facebook JavaScript SDK or perform what is called Server Flow Authentication. In this tutorial we will use the Facebook JavaScript SDK to perform authentication. The Facebook JavaScript SDK will handle all the details of displaying the login dialog, requesting permissions, and parsing the authentication cookie for the access token.

Adding the Facebook JavaScript SDK to Your Site

Add the following code right after the <body> tag on your web page.

<script>
        window.fbAsyncInit = function () {
            FB.init({
                appId: 'YOUR_APP_ID', // AppID goes here
                status: true, // check login status
                cookie: true, // enable cookies to allow server to access session
                xfbml: true, // parse XFBML
                version: 'v2.0' //Graph API version
            });

        // Initialization code goes here
        };

        // Load SDK Asynchronously
        (function (d, s, id) {
            var js, fjs = d.getElementsByTagName(s)[0];
            if (d.getElementById(id)) { return; }
            js = d.createElement(s); js.id = id;
            js.src = "//connect.facebook.net/en_US/all.js";
            fjs.parentNode.insertBefore(js, fjs);
        } (document, 'script', 'facebook-jssdk'));
</script>

Don’t forget to set the appId variable equal to the AppID of the Facebook application you created at the beginning of this tutorial.

Authenticating a User

We now have Facebook JavaScript SDK installed on our application. It’s time to create a Facebook Login button and place it on our web page. Add the highlighted code in your webpage.

</pre>
<form id="form1">
<div class="fb-login-button" data-send="true" data-width="600" data-show-faces="true" data-max-rows="5"></div>
</form>
<pre>

After the user has authenticated and authorized our application, we need to obtain the access token. For this we need to add the below JavaScript immediately after the // Additional initialization code goes here comment in the JavaScript we added earlier.

FB.Event.subscribe('auth.authResponseChange', function(response) {
    if (response.status === 'connected') {
        // the user is logged in and has authenticated your
        // app, and response.authResponse supplies
        // the user's ID, a valid access token, a signed
        // request, and the time the access token
        // and signed request each expire
        var uid = response.authResponse.userID;
        var accessToken = response.authResponse.accessToken;

        // TODO: Handle the access token here

    } else if (response.status === 'not_authorized') {
        // the user is logged in to Facebook,
        // but has not authenticated your app
    } else {
        // the user isn't logged in to Facebook.
    }
});

After obtaining the access token, we need to send it to the server. There are multiple ways of doing this but the easiest way is to perform an HTTP POST with the access token and redirect our user to a new page. Once we obtain the token from the server, the easiest way is to store it in the Session State and letASP.NET play with it. In order to do this place the below client-side JavaScript just after the // TODO: Handle the access token here comment in the previous step.

// Do a post to the server to finish the logon
var form = document.createElement("form");
form.setAttribute("method", 'post');
form.setAttribute("action", 'http://localhost:xxxx/MyFacebookApp/FacebookLogin.ashx');

var field = document.createElement("input");
field.setAttribute("type", "hidden");
field.setAttribute("name", 'accessToken');
field.setAttribute("value", accessToken);
form.appendChild(field);

document.body.appendChild(form);
form.submit();

Next step is to create a handler to receive the token and redirect the user. W’ll be using a Generic Handler to this. Create a new Generic Handler by right clicking on your project in Visual Studio >> Add New Item >> Select ‘Generic Handler’ from this list. Name it “FacebookLogin.ashx”.

public class FacebookLogin : IHttpHandler, System.Web.SessionState.IRequiresSessionState {

    public void ProcessRequest(HttpContext context) {
        var accessToken = context.Request["accessToken"];
        context.Session["AccessToken"] = accessToken;

        context.Response.Redirect("http://localhost:xxxx/MyFacebookApp/UserDetails.aspx");
    }

    public bool IsReusable {
        get { return false; }
    }
}

Using the Access Token

Now that we have successfully saved the access token to the session state we can make requests on behalf of that user when they are browsing our site.

var accessToken = Session["AccessToken"].ToString();
var client = new FacebookClient(accessToken);
dynamic result = client.Get("me", new { fields = "name, id, birthday" });
string name = result.name;
string id = result.id;
DateTime birthday = DateTime.Parse(result.birthday);

We are more concerned over determining the various likes of the user and their categories. Facebook Developer page provides Graph API Explorer tool for trying out your Get() requests. It’s always a good practice to verify and perfect your requests before incorporating in your application.

For our application, we will be making two Get() requests. One, for getting the basic details of the logged-in user, and the second for retrieving the likes of the user. Add the following code in your UserDetails.aspx.cs page.

var accessToken = Session["AccessToken"].ToString();
var client = new FacebookClient(accessToken);

dynamic myInfo = client.Get("me/", new { fields = "id, birthday, name" });
dynamic myLikes = client.Get("me/likes?limit=150", new { fields = "category, name, created_time, id" });

Notice the limit modifier in the above request. By default, Facebook Graph API returns only 25 results. In order to retrieve more results we use the limit modifier and provide the number of results you want to get. The result returned by the second request is of the following structure.

{
  "data": [
    {
      "category": "Computers/internet website",
      "name": "Android and Me",
      "created_time": "2014-01-22T20:48:53+0000",
      "id": "115561868082"
    },
    {
      "category": "School",
      "category_list": [
        {
          "id": "365182493518892",
          "name": "School"
        }
      ],
      "name": "St. Karen's High School",
      "created_time": "2013-10-30T16:55:31+0000",
      "id": "461179170627960"
    },
    {
      "category": "Musician/band",
      "name": "Deep Purple (1968-1976)",
      "created_time": "2013-09-25T15:41:11+0000",
      "id": "192121640808384"
    },
    {
      "category": "Tv show",
      "name": "The Simpsons",
      "created_time": "2013-09-24T16:10:49+0000",
      "id": "29534858696"
    }
  ]
}

The result above was returned as dynamic array which has been converted to JSON format and then Serialized to give it structure with intended formatting.

Since we have retrieved the data which we wanted, it’s time to address the elephant in the room. Yes, creating Nodes & Relationships, storing, indexing and retrieving data using Neo4J Graph Database.


Unless you want to be bleeding edge, it’s recommended to download the Major Stable Community Version. 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.

As you have done earlier with Facebook Third-Party installs using NuGet; We will be 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.

Once Neo4JClient is installed, we can reference it in our on-going application.

using Neo4jClient;
using Neo4jClient.Cypher;

Nodes, Relations & Indexes

Before we get down to coding we must decide on which Entities would act as a node in our graph, the relationship between them and on what your indexes would be based on. For our application, the logged-in Facebook User, his Likes and the Category of the like will be acting as Nodes.

Relationship between these entities could be formed as:

User->[interest_area]->Category-[includes]->Like

In the above two cases, interest_area and includes are the two relationships binding out three entities.

We will be creating indexes on out three entities i.e. User, Like & Category.

Now, we will be creating our three Entities and define their properties and initiate their relationships.

/// <summary>
/// Summary description for User
/// </summary>
public class User
{
    public string Id { get; set; }
    public string Birthday { get; set; }
    public string Username { get; set; }

    public User()
	{
		// TODO: Add constructor logic here
	}
}

public class Interest_Relationship : Relationship, IRelationshipAllowingSourceNode<User>, IRelationshipAllowingTargetNode<Category>
{
    public static readonly string TypeKey = "interest_area";

    public Interest_Relationship(NodeReference targetNode)
        : base(targetNode)
    { }

    public override string RelationshipTypeKey
    {
        get { return TypeKey; }
    }
}

We create similar classes for Likes and Category

/// <summary>
/// Summary description for Likes
/// </summary>
public class Likes
{
    public string Category { get; set; }
    public string Name { get; set; }
    public string Created_Time { get; set; }
    public string Id { get; set; }

    public Likes()
	{
		// TODO: Add constructor logic here
	}
}
///
/// Summary description for Category
///
public class Category
{
    public string Category_name { get; set; }

    public Category()
	{
		// TODO: Add constructor logic here
	}
}
public class Includes_Relationship : Relationship, IRelationshipAllowingSourceNode<Category>, IRelationshipAllowingTargetNode<Likes>
{
    public static readonly string TypeKey = "includes";

    public Includes_Relationship(NodeReference targetNode)
        : base(targetNode)
    { }

    public override string RelationshipTypeKey
    {
        get { return TypeKey; }
    }
}

All the above three files should reside in the App_Code folder for your website.

We now return back to our UserDetails.aspx.cs page. First off all we need to create a Graph-Context object. After creating the object we will connect to it.

GraphClient neo4jclient = new GraphClient(new Uri("http://localhost:7474/db/data"));
neo4jclient.Connect();

We will be now creating indexes on the three entities.

var accessToken = Session["AccessToken"].ToString();
var client = new FacebookClient(accessToken);

dynamic myInfo = client.Get("me/", new { fields = "id, birthday, name" });
dynamic myLikes = client.Get("me/likes?limit=150", new { fields = "category, name, created_time, id" });

GraphClient neo4jclient = new GraphClient(new Uri("http://localhost:7474/db/data"));
neo4jclient.Connect();

//Create Indexes
neo4jclient.CreateIndex("user", new IndexConfiguration() { Provider = IndexProvider.lucene, Type = IndexType.fulltext }, IndexFor.Node); // full text node index
neo4jclient.CreateIndex("like", new IndexConfiguration() { Provider = IndexProvider.lucene, Type = IndexType.exact }, IndexFor.Node); // exact node index
neo4jclient.CreateIndex("category", new IndexConfiguration() { Provider = IndexProvider.lucene, Type = IndexType.fulltext }, IndexFor.Node); // full text node index

As you can see we have created Full-Text Node Index for User and Category entities while Exact Node Index for Like entity. Scroll above to the Grey box to learn the difference.

Let’s create our nodes. First create an object on User class. Always use Cypher query to communicate with Neo4J. Analyze the code for creating a User node below and similarly create Category and Like nodes.

 //Create User Node
 User facebookUser = new User() { Id = myInfo.id, Username = myInfo.name, Birthday = myInfo.birthday };

var userRef = neo4jclient.Cypher
  .Create("(user:user {param})")
  .WithParam("param", facebookUser)
  .Return<User>("user")
  .Results
  .Single();

For creating Like nodes, iterate through the dynamic variable myLikes, returned by Facebook Graph API.

Creating Category nodes is a two-step process. If you have noticed, we do not have direct access to the Category list. We need to prepare a list containing all distinct Category types. Since we have already created Like nodes, firing a simple cypher on graph db makes it easy.

//Get Distinct Category Nodes
var resultCategory = neo4jclient.Cypher
    .Match("(likes)")
    .Where("likes:like")
    .Return<String>("DISTINCT likes.Category").Results;

Since now we do have the list of categories, we can iterate through it creating Category nodes. While iterating through the categories, we can create relationships between our three nodes. Refer the below code to do this.

//Get Distinct Category Nodes
var resultCategory = neo4jclient.Cypher
    .Match("(likes)")
    .Where("likes:like")
    .Return<String>("DISTINCT likes.Category").Results;

if (resultCategory != null)
{
    foreach (dynamic category in resultCategory)
    {
        //Creat Category Nodes
        Category likeCategory = new Category() { Category_name = category };
        var categoryNode = neo4jclient.Cypher
            .Create("(cat:category {param})")
            .WithParam("param", likeCategory)
            .Return<Category>("cat")
            .Results
            .Single();

        //Create User->Category Relationship
        neo4jclient.Cypher
            .Match("(a:user),(b:category)")
            .Where("a.Username='"+ facebookUser.Username +"' and b.Category_name='" + category + "'")
            .Create("(a)-[r:interest_area]->(b)")
            .ExecuteWithoutResults();

        //Create Category->Like Relationship
        neo4jclient.Cypher
            .Match("(a:category),(b:like)")
            .Where("a.Category_name='" + category + "' and b.Category='" + category + "'")
            .Create("(a)-[r:includes]->(b)")
            .ExecuteWithoutResults();
    }
}

Once you have followed and completed all of the above instructions, your job is nearly done. If you run your application at this moment, your webpage would not display anything because we have not yet visualized it. But having said that, if you still want to have a sneak-peek at what we have achieved so far, go to http://localhost:7474/. Click on the ‘Data Browser’ tab and fire the below cypher query.

MATCH (A:user)
RETURN A

The above cypher should return a single node. If you click on the node, you can view all its properties. Since it is a graph database you must be thinking of visualizing the data graphically. We will do it just now. After you have clicked on the node, go the top-right corner of the page. Choose the one which says “Switch to View Mode” on hovering. Clicking on it will give you a similar graph as below.

webadmin1

Clicking on the nodes will expand them, if you have configured their properties correctly. You can even create your own graph styles. Click and drag the nodes & relationships to play with them.

webadmin2

I hope this tutorial has been informative and up to your requirements. Feel free to post any comment or questions. I’ll be more than happy to help you out.

Cheers 🙂

What’s with the name?

I must admit, “the magic squares” is quiet an unorthodox name for a technical blog. Some of you might be even intrigued by it. Factually speaking, a magic square is a 2-Dimensional array of distinct positive numbers arranged in such a way that the sum of the n numbers in any horizontal, vertical, or main diagonal line is always the same number.

Magic-Square

Magic-Square

Then why in heaven did I chose this as the name of my blog!!The answer is right below…

For me, a magic square is more than a box filled with numbers. To me, it denotes symmetry, a collaboration of numbers, syncing in altogether to form something ingenious. A mathematical marvel.

This blog as well will be built on the very same foundations. The tutorials published on this blog will not only be consisting of multiple technologies, platforms, packages and APIs, but all of them coming together, syncing-in to form something out of the ordinary.

I will try to make the posts informative and easy to understand to the best of my ability.

Now comes your part. Share & comment if you like the content of the posts. Post queries, if you have any. I’ll do my best to answer them as early as possible. Hope it has something for everyone.

Cheers…