Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

neo4j

spatial

I have what appears to be a correctly configured spatial layer and index and can successfully query a node using findGeometriesWithinDistance REST API call.

POST /db/data/ext/SpatialPlugin/graphdb/findGeometriesWithinDistance {"layer":"geom","pointX":15.0,"pointY":60.0,"distanceInKm":100.0}

However, when querying using cypher, I get no results (I have tried reversing the order of 60.0 and 15.0 without luck):

START n=node:geom('withinDistance:[60.0, 15.0, 500.0]') return n;

Cyper returns:

==> +---+
==> | n |
==> +---+
==> +---+
==> 0 row
==> 
==> 13 ms

REST:

200 OK
==> [ {
==>   "paged_traverse" : "http://localhost:7474/db/data/node/14472/paged/traverse/{returnType}{?pageSize,leaseTime}",
==>   "outgoing_relationships" : "http://localhost:7474/db/data/node/14472/relationships/out",
==>   "data" : {
==>     "lon" : 15.2,
==>     "bbox" : [ 15.2, 60.1, 15.2, 60.1 ],
==>     "RaceName" : "Parador Es Muy Caliente",
==>     "lat" : 60.1,
==>     "gtype" : 1
==>   },
==>   "all_typed_relationships" : "http://localhost:7474/db/data/node/14472/relationships/all/{-list|&|types}",
==>   "traverse" : "http://localhost:7474/db/data/node/14472/traverse/{returnType}",
==>   "self" : "http://localhost:7474/db/data/node/14472",
==>   "all_relationships" : "http://localhost:7474/db/data/node/14472/relationships/all",
==>   "property" : "http://localhost:7474/db/data/node/14472/properties/{key}",
==>   "properties" : "http://localhost:7474/db/data/node/14472/properties",
==>   "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/14472/relationships/out/{-list|&|types}",
==>   "incoming_relationships" : "http://localhost:7474/db/data/node/14472/relationships/in",
==>   "incoming_typed_relationships" : "http://localhost:7474/db/data/node/14472/relationships/in/{-list|&|types}",
==>   "extensions" : {
==>   },
==>   "create_relationship" : "http://localhost:7474/db/data/node/14472/relationships"
==> } ]

REST Calls to reproduce: Create Layer:

POST /db/data/ext/SpatialPlugin/graphdb/addSimplePointLayer { "layer":"geom", "lat":"lat", "lon":"lon" }

Create Index:

POST /db/data/index/node/ {"name":"geom", "config":{"provider":"spatial", "geometry_type":"point","lat":"lat","lon":"lon"}}

Create Node:

POST /db/data/node {"lat":60.2,"lon":15.1,"RaceName":"Parador Es Muy Caliente"}

(In response, examine "self" and find nodeid)

Index the node:

POST /db/data/ext/SpatialPlugin/graphdb/addNodeToLayer {"layer":"geom", "node":"http://localhost:7474/db/data/node/###NEW_NODE_ID###"}

Find:

POST /db/data/ext/SpatialPlugin/graphdb/findGeometriesWithinDistance {"layer":"geom","pointX":15.0,"pointY":60.0,"distanceInKm":100.0}
like image 846
Troy Busot Avatar asked Jul 31 '13 09:07

Troy Busot


2 Answers

I investigated this, and it is related to an issue we have seen a few times. There is an inconsistency in the design of the spatial library in that there are two ways to add a node to the spatial index. The one is to add it to the Layer (using the addNodeToLayer REST call), and this uses the underlying Java API which directly connects the node into the RTree as part of the same graph. The other is to create a proxy node in the index graph so that your domain graph is not connected to the index graph. This second approach is only taken by the IndexProvider interface (using the /db/data/index/node/geom REST call).

If you call both methods, the node is added twice, once directly and once by proxy. The problem is that the Cypher withinDistance index query accesses only the IndexProvider interface, and will only return nodes that are NOT also connected to the index. So if you add the node in both ways, it will not be returned.

So you need to add it only one of the two ways. I did not see in your original email any mention of addNodeToLayer, so I suspect that SDN might be calling addNodeToLayer (perhaps Michael can comment), in which case you cannot use the cypher call.

During my testing, I was able to manually remove the one index relationship using Cypher like this:

START n=node(13065) MATCH (n)<-[r:RTREE_REFERENCE]-() DELETE r

Replace the number 13065 with your node id for the original node.

I did the following in the neo4j browser (in 2.1.2):

:POST /db/data/ext/SpatialPlugin/graphdb/addSimplePointLayer { "layer":"geom", "lat":"lat", "lon":"lon" }
:POST /db/data/index/node/ {"name":"geom", "config":{"provider":"spatial", "geometry_type":"point","lat":"lat","lon":"lon"}}
:POST /db/data/node {"lat":60.2,"lon":15.1,"RaceName":"Parador Es Muy Caliente"}
:POST /db/data/index/node/geom {"value":"dummy","key":"dummy", "uri":"http://localhost:7474/db/data/node/13071"}

This created a graph with the node not directly connect to the index. In this case the REST call 'findGeometriesWithinDistance' does not work (uses standard Java API), while the cypher 'withinDistance' does work. I tested with this command:

start n = node:geom("withinDistance:[60.2,15.1,100.0]") return n

Note that unfortunately this API puts the order as lat,lon, instead of the more standard lon,lat.

Then I also added to the layer (ie. add directly to the index graph):

:POST /db/data/ext/SpatialPlugin/graphdb/addNodeToLayer {"layer":"geom", "node":"http://localhost:7474/db/data/node/13071"}

Now when I search with the cypher command I still get the same correct answer, but when I search with the REST command:

:POST /db/data/ext/SpatialPlugin/graphdb/findGeometriesWithinDistance {"layer":"geom","pointX":15.0,"pointY":60.0,"distanceInKm":100.0}

I find this returns the proxy node instead of the original node.

like image 60
Craig Taverner Avatar answered Nov 10 '22 11:11

Craig Taverner


this is a bug, see https://github.com/neo4j/spatial/issues/106 if you want, feel free to investigate, seems to be the iteration in SpatialRecordHits.java!

Meanwhile, make sure to add the node to the index before querying via the index, as that creates the proper node structure.

like image 45
Peter Neubauer Avatar answered Nov 10 '22 13:11

Peter Neubauer