PHP

Neo4j Wiki から

目次

[edit] There are different ways to run PHP-frontend code with Neo4j:

[edit] A Small Success Story

A small success story from a PHP developer , who would like to do as little Java-Programming as needed. The current application I am developing needs a GraphDB and Neo4j seems to be a very good candidate. I've examined the options above and chose the php-java-bridge and have had some success, which I would like to report on.

[edit] Why Java Bridge

  • Protobuffers does not mention PHP in their welcome screen so I avoided it. (also I prefer to stay away from Google when possible ;) )
  • I have not yet tried Java/Jersey. It may be a viable option, but I've shied away from it at first due to anticipated setup complications.
  • I was not able to compile Thrift on my computer (Suse Linux 11.1) and gave up.
  • I decided against Resin/Qeurcus because my application will likely be over 95% PHP and it seems silly to compile all of this into Java, just to be able to use Neo
  • Influencing the PHP bindings is beyond my control.
  • Another option is the Zend Java Bridge but AFAIK this is not open source and therefore must be purchased.

So the only option left was the Java Bridge. I had some major #Installation Headaches getting the Java Bridge running on my system but after a few days I now am able to access the Neo4j Classes and and create a NeoDB from a PHP application. I'm still in the early stages of development and there is much to be done but I'd like to share what I've achieved so far. Maybe this is a help for some of you. Perhaps someone has some other ideas. Any comments and suggestions are welcome.

The Java Bridge allows one from PHP to access Java Class Methods. I've written a Java Class and a PHP Class which correspond and communicate with one another, in order to perform some of the basic Neo4j operations. So far I can create nodes and relationships (including Lucene Indexing via the Neo4j Indexing utility). This example now includes traversal functionality.

[edit] PHP/Java Classes

In Java I have the following Class (some of the operations are peculiar to my application):

import java.util.HashMap;
import org.neo4j.graphdb.*;
import org.neo4j.kernel.EmbeddedGraphDatabase;
import org.neo4j.index.IndexService;
import org.neo4j.index.lucene.LuceneIndexService;

public class phpNeoGateway {
    private static GraphDatabaseService graphDb;
    private static IndexService indexService;
    private static Traverser nodeTraverser;

    public enum MyRelationshipTypes implements RelationshipType {
        INTERPRETED, DEDUCES, REFERENCE
    }

    public static void startGraphDb(String dbPath) {
    	 graphDb = new EmbeddedGraphDatabase( dbPath );
         indexService = new LuceneIndexService( graphDbDb );
    }
    
    public static void stopGraphDb() {
    	graphDb.shutdown();
    }
    
    public static long createMapNode(String newTitle, String nodeType) {
    	long rv;
    	Transaction tx = graphDb.beginTx();
    	try {
    		Node newNode = indexService.getSingleNode("title", newTitle);
    		if (newNode == null) {
    			newNode = graphDb.createNode();
    			newNode.setProperty("title",newTitle);
    			newNode.setProperty("node_type",nodeType);
    			indexService.index( newNode, "title", newNode.getProperty( "title" ) );
    		}
    		rv = newNode.getId();
            tx.success();
    	} finally {
    		tx.finish();
    	}
    	
    	return rv;
    }
    
    public static void createRelationship(long parentId, long hermId, long childId) {
    	Transaction tx = neoDb.beginTx();
    	try {
    		Node parentNode = graphDb.getNodeById(parentId);
    		Node hermNode = graphDb.getNodeById(hermId);
    		Node childNode = graphDb.getNodeById(childId);

    		Relationship pToH = parentNode.createRelationshipTo( hermNode, MyRelationshipTypes.INTERPRETED );    	
    		Relationship hToC = hermNode.createRelationshipTo( childNode, MyRelationshipTypes.DEDUCES );

    		Iterable<Relationship> currentRelationships = hermNode.getRelationships(Direction.OUTGOING);
    		final int relCount = relationshipCount(currentRelationships); 
    		
    		pToH.setProperty("interpretation_id", Integer.toString(relCount));
    		hToC.setProperty("interpretation_id", Integer.toString(relCount));
    		
    		tx.success();
    	} finally {
    		tx.finish();
    	}
    }
    
    public static int relationshipCount(Iterable<Relationship> relIterator) {
        int count = 0;
        while (relIterator.iterator().hasNext()) {
        	relIterator.iterator().next();
            ++count;
        }
        return count;
    }

    public static void startTraverser(long startNodeId) {
    	Transaction tx = neoDb.beginTx();
    	try {
            Node referenceNode = graphDb.getReferenceNode();
            Node startNode = graphDb.getNodeById(startNodeId);
            referenceNode.createRelationshipTo( startNode, MyRelationshipTypes.REFERENCE );
    		nodeTraverser = startNode.traverse(
    				Traverser.Order.DEPTH_FIRST,
    				StopEvaluator.DEPTH_ONE,
    				ReturnableEvaluator.ALL,
    				MyRelationshipTypes.INTERPRETED,
    				Direction.BOTH,
    				MyRelationshipTypes.DEDUCES,
    				Direction.BOTH );        
    		tx.success();
    	} finally {
    		tx.finish();
    	}
    }

    public static String advanceTraverser() {
        String rv;
        Transaction tx = neoDb.beginTx();
    	try {
    		if (nodeTraverser.iterator().hasNext()) {
    			Node currentNode = nodeTraverser.iterator().next();
                // Create JSON String
                rv = "{";
                rv += "\"id\":\"" + (String) Long.toString(currentNode.getId() ) + "\"";
                rv += ",\"title\":\"" + (String) currentNode.getProperty( "title" ) + "\"";
                rv += ",\"node_type\":\"" + (String) currentNode.getProperty( "node_type" ) + "\"";

                Iterable<Relationship> nodeRelationships = currentNode.getRelationships(Direction.BOTH);
                int count = 0;
                while (nodeRelationships.iterator().hasNext()) {
                    Relationship rel = nodeRelationships.iterator().next();
                    if (rel.isType(MyRelationshipTypes.INTERPRETED) || rel.isType(MyRelationshipTypes.DEDUCES)) {
                        ++count;
                        rv += ",\"interpretation_" + Integer.toString(count) + "\": {";
                        rv += "\"relationship_type\":\"" + (String) rel.getType().name() + "\"";
                        rv += ",\"interpretation_id\":\"" + (String) rel.getProperty( "interpretation_id" ) + "\"";
                        rv += ",\"from\":\"" + (String) Long.toString(rel.getStartNode().getId() ) + "\"";
                        rv += ",\"to\":\"" + (String) Long.toString(rel.getEndNode().getId() ) + "\"";
                        rv += "}";
                    }
                }
                rv += "}";
    		} else {
    			rv = null;
    		}
    		tx.success();
    	} finally {
    		tx.finish();
    	}
    	return rv;
    }
}

This is the corresponding PHP class:

<?php

require_once('/srv/www/htdocs/JavaBridge/java/Java.inc');

class neoManager {	
    private	$_neoPath = '/home/and/computer/development/neo/current/';
    private	$_appPath = '/home/and/computer/eclipse/galileo/phpNeoGateway/';
	
	public function __construct($dbPath) {
		$javaClasspath  = $this->_neoPath . 'geronimo-jta_1.1_spec-1.1.1.jar;'; 
		$javaClasspath .= $this->_neoPath . 'neo4j-kernel-1.0.jar;'; 
		$javaClasspath .= $this->_neoPath . 'neo4j-index-1.0.jar;';
		$javaClasspath .= $this->_neoPath . 'neo4j-commons-1.0.jar;';
		$javaClasspath .= $this->_neoPath . 'lucene-core-2.9.1.jar;'; 
		$javaClasspath .= $this->_appPath . 'phpNeoGateway.jar'; 
		java_require( $javaClasspath );
		java("phpNeoGateway")->startGraphDb( $dbPath );
	}
	
	public function __destruct() {
		java('phpNeoGateway')->stopGraphDb();		
	}
	
	public function getNode($nodeId) {
		
	}
	
	public function createPropNode($newTitle) {    	
    	return java('phpNeoGateway')->createMapNode($newTitle, 'proposition');		
	}

	public function createHermNode($newTitle) {    	
    	return java('phpNeoGateway')->createMapNode($newTitle, 'hermeneutic');		
	}
	
	public function createRelationship($parentId, $hermId, $childId) {
		java('phpNeoGateway')->createRelationship($parentId, $hermId, $childId);
	}

	public function startTraverser($nodeStartId) {
		java('phpNeoGateway')->startTraverser($nodeStartId);		
	}

	public function advanceTraverser() {
        $json = java('phpNeoGateway')->advanceTraverser(); 
        //echo $json.'<hr/>';
        //var_dump(json_decode($json, true));
        //echo '<hr/>';
		return json_decode($json, true);		
	}
}

?>

What I've tried to do, is to implement the necessary Neo4j operations in a Java class in such a way that I can perform them from PHP with a moderate level of abstraction. Certainly with some ingenuity, this can be modified for your specific application.

[edit] Installation Headaches

On my computer I have Suse Linux 11.1 64bit with Apache2, Tomcat6 and Java 1.6 Iced Tea installed. I had the following problems getting the Java Bridge to work properly.

  • Tomcat6 can be installed easily using Yast. The only hiccup was the JAVA_HOME variable in "/etc/sysconfig/tomcat6", which must be set to (JAVA_HOME="/usr/lib64/jvm/java") so that tomcat knows where the java binary is located (my installation).
  • With Java Bridge I had more problems than I bargained for :(. After following the installation instructions the critical problem, was that the file "JavaBridge.jar" was missing in the directory "/usr/share/tomcat6/webapps/JavaBridge/java". After copying this file to the directory everything worked fine.
    • Also in the Java Bridge file "/usr/share/tomcat6/webapps/JavaBridge/java/java.inc" I have line #4: define ("JAVA_HOSTS", 9267); define ("JAVA_SERVLET", false); uncommented. Without this the Java Bridge would not work.
Neo4j のサイト
ツールボックス