Neo4j Spatial over REST through the JAVA API not w

2019-07-20 18:06发布

问题:

I'm working on a Grails app over Neo4J which I'd like to also export as a GIS database.

Looking at the examples for how to use neo4j in GeoServer/uDig it appears that the Spatial integration is only via embedded neo4j databases.

Does anyone know whether it's possible to set things up so that my Neo4J is available over REST, so that I can interface to it from a variety of places?

At first sight it appears that it ought to be possible:

// Works with this embedded database
//def graphDb = new GraphDatabaseFactory().newEmbeddedDatabase("/tmp/foo.db");

// Doesn't work with this REST database
graphDb = new RestGraphDatabase("http://localhost:7474/db/data");

Transaction tx = graphDb.beginTx()

SpatialDatabaseService spatialService = new SpatialDatabaseService(graphDb)
SimplePointLayer layer = spatialService.createSimplePointLayer("points")

With an embedded database, the spatial index gets created just fine. However, with the REST database, I just get a null pointer:

Caused by NullPointerException: null
->>  149 | createCompiler in org.neo4j.cypher.ExecutionEngine
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|     48 | <init>    in     ''
|     59 | createInnerEngine in org.neo4j.cypher.javacompat.ExecutionEngine
|     43 | <init>    in     ''
|     41 | getReferenceNode in org.neo4j.gis.spatial.utilities.ReferenceNodes
|     78 | getSpatialRoot in org.neo4j.gis.spatial.SpatialDatabaseService
|    114 | getLayer  in     ''
|    259 | containsLayer in     ''
|    303 | createLayer in     ''
|    287 | createSimplePointLayer in     ''
|    267 | createSimplePointLayer in     ''
|     37 | <init>    in net.foo.db.neo4j.Neo4JService

The SpatialDatabaseService takes a GraphDatabaseService, so I'm confused as to why it doesn't work with a REST one.

Is this a bug or a feature (or a misunderstanding on my part?)

I can, of course, use the create index API to create a spatial index:

graphDb.index().forNodes( "points", ["provider": "spatial", "geometry_type": "point", "lat": "lat", "lon":"lon"])

so that works, but I can't create new layer that way.

回答1:

The RestGraphDatabase is a fake database which doesn't offer all capabilities. It could be made work in theory but would be very wasteful as each presumably embedded operation would go over the wire as http requests.

Install Spatial as Plugin to your server and then access it via the plugin REST methods.

See: http://neo4j-contrib.github.io/spatial/#spatial-server-plugin



回答2:

Though I don't really understand what you are doing with this Grail App and stuff, from the look of your exceptions, it looks like you are trying to do something like this:

ExecutionEngine executionEngine = new ExecutionEngine(graphDatabaseService);

where ExecutionEngine is from cypher.javacompat and GraphDatabaseService is pointing to RestGraphDatabase.

ExecutionEngine builds upon our internal Kernel API, which it can only get from an embedded kind of database.

To run Cypher queries on a RestGraphDatabase, you need grab its RestAPI from getRestAPI, and use the query method on that.

A post on this google groups explains this: https://groups.google.com/forum/#!topic/neo4j/Q6lsOakSgyA

Below is a sample program that I made which uses the RestGraphDatabase to create and execute queries. Hope this helps.

package rash.experiments.neo4j;

import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.Transaction;
import org.neo4j.rest.graphdb.RestGraphDatabase;
import org.neo4j.rest.graphdb.query.RestCypherQueryEngine;
import org.neo4j.rest.graphdb.util.QueryResult;

public class Neo4JRestTest
{
    private static enum RelType implements RelationshipType
    {
        KNOWS
    }

    public static void main(String args[])
    {
        RestGraphDatabase graphDatabaseService = new RestGraphDatabase("http://10.20.230.12:7474/db/data/");
        RestCypherQueryEngine executionEngine = new RestCypherQueryEngine(graphDatabaseService.getRestAPI());

        try(Transaction transaction = graphDatabaseService.beginTx())
        {
            Node rash = graphDatabaseService.createNode();
            rash.setProperty("userId", 4);
            rash.setProperty("username", "rash");
            rash.setProperty("name", "Rahul Chaudhary");

            Node honey = graphDatabaseService.createNode();
            honey.setProperty("userId", 5);
            honey.setProperty("username", "honey");
            honey.setProperty("name", "Honey Anant");

            Relationship knowsRelationship = rash.createRelationshipTo(honey, RelType.KNOWS);
            knowsRelationship.setProperty("since", 2011);

            transaction.success();
        }

        try(Transaction transaction = graphDatabaseService.beginTx())
        {
            QueryResult<Map<String,Object>> executionResult = executionEngine.query("match (node) return node", null);
            Iterator<Map<String, Object>> resourceIterator = executionResult.iterator();

            while(resourceIterator.hasNext())
            {
                Set<Entry<String, Object>> map = resourceIterator.next().entrySet();
                for(Entry<String, Object> entry : map)
                {
                    Node node = (Node) entry.getValue();
                    System.out.println("UserId: " + node.getProperty("userId"));
                    System.out.println("Username: " + node.getProperty("username"));
                    System.out.println();
                }

                System.out.println("--------------------------\n");
            }

            transaction.success();
        }
    }
}