6
votes

I'm hoping someone can provide some updated clarification on adding nodes to Spatial. The best instructions I can find is:

Neo4j Spatial 'WithinDistance' Cypher query returns empty while REST call returns data

However it's almost 2 years old and has some contradictory information with an acknowledged bug (https://github.com/neo4j-contrib/spatial/issues/106), which appears to still be open.

I also found this tutorial:

http://mattbanderson.com/setting-up-the-neo4j-spatial-extension/

Which says we should add the node to the layer AND insert the Neo4j ID# into the node as a property, but NOT insert the node to the geom index.

My main priority here is that I be able to query via Cypher (within the browser) but we will eventually want to be able to query via REST as well. So, ideally i'd like to insert the nodes in such a way that we can do both.

So, my questions are:

1) What are the correct steps here to allow querying via both REST and Cypher?

2) If I call /addSimplePointLayer and then /index/node to add the Spatial index (both via cURL or REST), can I use LOAD CSV to insert nodes and be able to query Spatial Plugin via both REST and Cypher?

3) If I am using REST to insert my nodes, what calls (and in what order) would I need to make in order to ensure that I can query via both REST and Cypher (web browser)?

Thanks, I'm looking forward to getting this all worked out!!

1

1 Answers

13
votes

question 1

You first need to initialize once a layer and create the spatial index using the REST calls:

POST /db/data/ext/SpatialPlugin/graphdb/addSimplePointLayer HTTP/1.1
Host: localhost:7474
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache

{ 
    "layer" : "geom", 
    "lat" : "lat", 
    "lon" : "lon" 
}

and:

POST /db/data/index/node/ HTTP/1.1
Host: localhost:7474
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache

{ 
    "name" : "geom", 
    "config" : { 
        "provider" : "spatial", 
        "geometry_type" : "point", 
        "lat" : "lat", 
        "lon" : "lon" 
    } 
}

Create a node with lon/lat properties using Cypher via the transactional endpoint:

POST /db/data/transaction/commit HTTP/1.1
Host: localhost:7474
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache

{
  "statements" : [ 
  {
    "statement" : "create (city:City {data}) return id(city)",
    "parameters" : {
      "data" : {
        "name" : "MyTown",
        "lon": 15.2,
        "lat": 60.1
      }
    }
  } 
  ]
}

and add it to the spatial index - be sure to adopt the node id with the id of the node returned from the previous request:

POST /db/data/ext/SpatialPlugin/graphdb/addNodeToLayer HTTP/1.1
Host: localhost:7474
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache

{ 
    "layer": "geom", 
    "node": "http://localhost:7474/db/data/node/<my_nodeid_goes_here>" 
}

In order to enable Spatial play nice with Cypher a hack is required: every geo-indexed node should carry a property called id with the value of the node id. This can be accomplished with a simple cypher statement (the example below does this for all City nodes):

POST /db/data/transaction/commit HTTP/1.1
Host: localhost:7474
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache

{ 
    "statements" : [ 
        { "statement" : "match (n:City) set n.id=id(n)" } 
    ] 
}

With that in place you can use Cypher for geo queries, e.g.:

POST /db/data/transaction/commit HTTP/1.1
Host: localhost:7474
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache

{
  "statements" : [ 
  {
    "statement" : "start city = node:geom('withinDistance:[60.1,15.2, 100.0]') return city",
    "parameters" : {}
  } 
  ]
}

NB: for withinDistance you have to specify lat,lon, distanceInKm.

question 2

As described above you need to have a separate REST call for adding a node to the spatial index. This is currently not possible with Cypher directly. As a workaround use LOAD CSV to create the nodes with lon/lat properties. In a preprocessing step run a statement like MATCH (n:City) where not has(n.id) set n.id = id(n) return id(n) as id. This will set the id properties (the hack described above) and returns a list of ids of the new nodes. For each of them emit the REST call to add a node to the geo index.

question 3

Has been answered already above :-)