Introduction to Neo4j

Neo4j is an open-source graph database, implemented in Java.It is a part of the NoSQL movements. It is available in a GPLv3 Community edition, and  under AGPLv3 for the Advanced and Enterprise editions.
In this post we are going to see how to use the embedded Neo4j Community edition to manage graphs.

The example here is based on Neo4j Community Edition (neo4j-community-1.7.2), the needed jars to include are: neo4j-lucene-index-1.7.2.jarlucene-core-3.5.0.jarneo4j-kernel-1.7.2.jarYou need also to add jta.jar (download it here) to your Java CLASSPATH to avoid following exception "NoClassDefFoundError: javax/transaction/TransactionManager". This exception is caused when you try to create a new database or openning a connection to an existent one. You can find more details about this very common exception in this post.

The following class provides an abstarction for most common Neo4j API calls, including opening/closing connection to the database, creating nodes with attributes, looking for a node/edge based on specific values of a certain attribute, etc.

import java.io.File;
import java.util.Map;

import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.ReturnableEvaluator;
import org.neo4j.graphdb.StopEvaluator;
import org.neo4j.graphdb.Traverser;
import org.neo4j.graphdb.Traverser.Order;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.neo4j.graphdb.index.Index;
import org.neo4j.kernel.EmbeddedGraphDatabase;

public class GraphManager {

 private static GraphDatabaseService sGraphDb; 
 private static Index<node> sNodeIndex;
 
 /** Opening a connection if the database already exist, if not the create a new one */
 public static GraphDatabaseService openConnection() {
  System.out.println("Opening connection (" + sGraphDb + ") to Neo4j Graph database.");
  sGraphDb = (EmbeddedGraphDatabase) new GraphDatabaseFactory().newEmbeddedDatabase( Constants.DB_PATH );
  sNodeIndex = sGraphDb.index().forNodes( "nodes" );
  registerShutdownHook( sGraphDb );
  return sGraphDb;
 }

 /** Creating a new node with the provided attributes */
 public static Node createNode(Map<string, string> attributes) {
  Node node = sGraphDb.createNode();
  if(attributes != null)
   for(String key :attributes.keySet()) {  
    node.setProperty(key, attributes.get(key));
   }
  return node;
 }
 
 /** Using provided attributes to Index a node */
 public static void indexNode(Node node, Map<string, string=""> attributes) {
  if(attributes != null)
   for(String key :attributes.keySet()) {  
    sNodeIndex.add( node, key, attributes.get(key));
   }
 }
 
 /** Find node given that have a specific value for the provided attribute */
 public static Node findNode(String key, String value) {
  return sNodeIndex.get(key, value).getSingle();
 }
 
 /** Allows to get next or previous nodes of a given type of link for nodes 
  * @param direction outgoing (next nodes) or incoming (previous nodes)
  * @param traversalOrder specifies how to explore the next nodes in depth or breath 
  * */
 public static Traverser nearbyNodes(Node node, RelationshipType type, Direction direction, Order traversalOrder)
 {
     return node.traverse(traversalOrder, 
       StopEvaluator.END_OF_GRAPH, 
       ReturnableEvaluator.ALL_BUT_START_NODE, 
       type, direction); 
 }
 
 /** Create a link between two nodes of a specific type and attributes 
  * @param from source node
  * @param to destination node
  * @param type of link between two nodes
  * @param attributes of this link
  * */
 public static Relationship createLink(Node from, Node to, RelationshipType type, Map<string, string=""> attributes) {
  Relationship link = from.createRelationshipTo(to, type);
  if(attributes != null)
   for(String key :attributes.keySet()) {  
    link.setProperty(key, attributes.get(key));
   }
  return link;
 }
 
 /** Close (shutdown) connection to database */
 public static void closeConnection() {
  System.out.println("Closing connection (" + sGraphDb + ") to Neo4j Graph database.");
  if(sGraphDb != null)
   sGraphDb.shutdown();  
 }
  
 /** Clean up before closing connection to database */
 private static void registerShutdownHook( final GraphDatabaseService graphDb ) {     
     Runtime.getRuntime().addShutdownHook( new Thread()
     {
         @Override
         public void run()
         {
             graphDb.shutdown();
         }
     } );
 }
 
 public static void clearDatabase() {
  deleteFileOrDirectory(new File(Constants.DB_PATH));  
 }
 
 private static void deleteFileOrDirectory( final File file )
    {
        if ( !file.exists() )
        {
            return;
        }

        if ( file.isDirectory() )
        {
            for ( File child : file.listFiles() )
            {
                deleteFileOrDirectory( child );
            }
        }
        else
        {
            file.delete();
        }
    }
}
Here is an example of code based on the previous class:
GraphDatabaseService graphDb = GraphManager.openConnection();
Transaction tx = graphDb.beginTx();
try {
    HashMap<string, string> attributes = new HashMap<string, string="">();
    attributes.put("identifier", "first");
    attributes.put("message", "Hello, ");
    Node firstNode = GraphManager.createNode(attributes);
    GraphManager.indexNode(firstNode, attributes);
    System.out.print( firstNode.getProperty( "message" ) );

    attributes.put("identifier", "second");
    attributes.put("message", "World!");
    Node secondNode = GraphManager.createNode(attributes);
    GraphManager.indexNode(secondNode, attributes);
    System.out.print( relationship.getProperty( "message" ) );

    attributes.put("message", "brave Neo4j ");
    relationship = GraphManager.createLink(firstNode, secondNode, RelTypes.KNOWS, attributes); 
    System.out.println( secondNode.getProperty( "message" ) );

    tx.success();
} finally {
    tx.finish();
}
GraphManager.closeConnection();
GraphManager.clearDatabase();

Aucun commentaire:

Enregistrer un commentaire