Neo4j Spatial: Strange caset exception while using startNearestNeighborLatLonSearch

48 views
Skip to first unread message

Alireza Rezaei Mahdiraji

unread,
Aug 7, 2015, 7:19:30 AM8/7/15
to Neo4j

Hi,

I get the following cast exception while using startNearestNeighborLatLonSearch method:

Exception in thread "main" java.lang.ClassCastException: java.lang.Double cannot be cast to [B

my code is as follows:

Layer layer = spatialDbInstance.getLayer("mylayer");
Coordinate coord = new Coordinate(0.0d, 0.0d);
List<Node> nodes = GeoPipeline.startNearestNeighborLatLonSearch(layer, coord, 1.0).toNodeList();


Basically, I am trying to find all other points within distance one of the origin (i.e., (0.0., 0.0) ).


Cheers,
Alireza

Alireza Rezaei Mahdiraji

unread,
Aug 7, 2015, 7:44:55 AM8/7/15
to Neo4j

I just tried and got similar error with startNearestNeighborSearch method.

I am using neo4j 2.3.0-M01 maven repo.

Cheers,
Alireza

Michael Hunger

unread,
Aug 8, 2015, 5:10:18 PM8/8/15
to ne...@googlegroups.com
Can you provide the full stacktrace.

Michael

--
You received this message because you are subscribed to the Google Groups "Neo4j" group.
To unsubscribe from this group and stop receiving emails from it, send an email to neo4j+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Alireza Rezaei Mahdiraji

unread,
Aug 8, 2015, 5:26:12 PM8/8/15
to Neo4j

Here are the stacks for the two cases (very similar):


Exception in thread "main" java.lang.ClassCastException: java.lang.Double cannot be cast to [B
    at org.neo4j.gis.spatial.WKBGeometryEncoder.decodeGeometry(WKBGeometryEncoder.java:41)
    at org.neo4j.gis.spatial.filter.SearchIntersectWindow.onEnvelopeIntersection(SearchIntersectWindow.java:48)
    at org.neo4j.gis.spatial.rtree.filter.AbstractSearchEnvelopeIntersection.geometryMatches(AbstractSearchEnvelopeIntersection.java:45)
    at org.neo4j.gis.spatial.rtree.RTreeIndex$SearchEvaluator.checkPosition(RTreeIndex.java:286)
    at org.neo4j.gis.spatial.rtree.RTreeIndex$SearchEvaluator.isStopNode(RTreeIndex.java:299)
    at org.neo4j.kernel.impl.traversal.OldTraverserWrapper$Pruner.evaluate(OldTraverserWrapper.java:260)
    at org.neo4j.graphdb.traversal.Evaluator$AsPathEvaluator.evaluate(Evaluator.java:69)
    at org.neo4j.kernel.impl.traversal.MultiEvaluator.evaluate(MultiEvaluator.java:62)
    at org.neo4j.kernel.impl.traversal.MonoDirectionalTraverserIterator.evaluate(MonoDirectionalTraverserIterator.java:61)
    at org.neo4j.kernel.impl.traversal.TraversalBranchImpl.evaluate(TraversalBranchImpl.java:125)
    at org.neo4j.kernel.impl.traversal.TraversalBranchImpl.initialize(TraversalBranchImpl.java:130)
    at org.neo4j.kernel.impl.traversal.TraversalBranchImpl.next(TraversalBranchImpl.java:151)
    at org.neo4j.kernel.impl.traversal.TraversalBranchWithState.next(TraversalBranchWithState.java:32)
    at org.neo4j.kernel.impl.traversal.StartNodeTraversalBranch.next(StartNodeTraversalBranch.java:50)
    at org.neo4j.graphdb.traversal.PreorderDepthFirstSelector.next(PreorderDepthFirstSelector.java:49)
    at org.neo4j.kernel.impl.traversal.MonoDirectionalTraverserIterator.fetchNextOrNull(MonoDirectionalTraverserIterator.java:70)
    at org.neo4j.kernel.impl.traversal.MonoDirectionalTraverserIterator.fetchNextOrNull(MonoDirectionalTraverserIterator.java:36)
    at org.neo4j.helpers.collection.PrefetchingIterator.peek(PrefetchingIterator.java:60)
    at org.neo4j.helpers.collection.PrefetchingIterator.hasNext(PrefetchingIterator.java:46)
    at org.neo4j.helpers.collection.PrefetchingIterator.next(PrefetchingIterator.java:75)
    at org.neo4j.kernel.impl.traversal.OldTraverserWrapper$TraverserImpl.next(OldTraverserWrapper.java:86)
    at org.neo4j.kernel.impl.traversal.OldTraverserWrapper$TraverserImpl.next(OldTraverserWrapper.java:47)
    at org.neo4j.gis.spatial.filter.SearchRecords.next(SearchRecords.java:53)
    at org.neo4j.gis.spatial.filter.SearchRecords.next(SearchRecords.java:29)
    at org.neo4j.gis.spatial.pipes.GeoPipeline$1.next(GeoPipeline.java:134)
    at org.neo4j.gis.spatial.pipes.GeoPipeline$1.next(GeoPipeline.java:126)
    at org.neo4j.gis.spatial.pipes.impl.LastElementIterator.next(LastElementIterator.java:19)
    at org.neo4j.gis.spatial.pipes.impl.IdentityPipe.processNextStart(IdentityPipe.java:18)
    at org.neo4j.gis.spatial.pipes.impl.AbstractPipe.next(AbstractPipe.java:72)
    at org.neo4j.gis.spatial.pipes.AbstractGeoPipe.processNextStart(AbstractGeoPipe.java:49)
    at org.neo4j.gis.spatial.pipes.AbstractGeoPipe.processNextStart(AbstractGeoPipe.java:31)
    at org.neo4j.gis.spatial.pipes.impl.AbstractPipe.next(AbstractPipe.java:72)
    at org.neo4j.gis.spatial.pipes.impl.Pipeline.next(Pipeline.java:113)
    at org.neo4j.gis.spatial.pipes.GeoPipeline.toNodeList(GeoPipeline.java:1015)

   

Exception in thread "main" java.lang.ClassCastException: java.lang.Double cannot be cast to [B
    at org.neo4j.gis.spatial.WKBGeometryEncoder.decodeGeometry(WKBGeometryEncoder.java:41)
    at org.neo4j.gis.spatial.filter.SearchIntersectWindow.onEnvelopeIntersection(SearchIntersectWindow.java:48)
    at org.neo4j.gis.spatial.rtree.filter.AbstractSearchEnvelopeIntersection.geometryMatches(AbstractSearchEnvelopeIntersection.java:45)
    at org.neo4j.gis.spatial.rtree.RTreeIndex$SearchEvaluator.checkPosition(RTreeIndex.java:286)
    at org.neo4j.gis.spatial.rtree.RTreeIndex$SearchEvaluator.isStopNode(RTreeIndex.java:299)
    at org.neo4j.kernel.impl.traversal.OldTraverserWrapper$Pruner.evaluate(OldTraverserWrapper.java:260)
    at org.neo4j.graphdb.traversal.Evaluator$AsPathEvaluator.evaluate(Evaluator.java:69)
    at org.neo4j.kernel.impl.traversal.MultiEvaluator.evaluate(MultiEvaluator.java:62)
    at org.neo4j.kernel.impl.traversal.MonoDirectionalTraverserIterator.evaluate(MonoDirectionalTraverserIterator.java:61)
    at org.neo4j.kernel.impl.traversal.TraversalBranchImpl.evaluate(TraversalBranchImpl.java:125)
    at org.neo4j.kernel.impl.traversal.TraversalBranchImpl.initialize(TraversalBranchImpl.java:130)
    at org.neo4j.kernel.impl.traversal.TraversalBranchImpl.next(TraversalBranchImpl.java:151)
    at org.neo4j.kernel.impl.traversal.TraversalBranchWithState.next(TraversalBranchWithState.java:32)
    at org.neo4j.kernel.impl.traversal.StartNodeTraversalBranch.next(StartNodeTraversalBranch.java:50)
    at org.neo4j.graphdb.traversal.PreorderDepthFirstSelector.next(PreorderDepthFirstSelector.java:49)
    at org.neo4j.kernel.impl.traversal.MonoDirectionalTraverserIterator.fetchNextOrNull(MonoDirectionalTraverserIterator.java:70)
    at org.neo4j.kernel.impl.traversal.MonoDirectionalTraverserIterator.fetchNextOrNull(MonoDirectionalTraverserIterator.java:36)
    at org.neo4j.helpers.collection.PrefetchingIterator.peek(PrefetchingIterator.java:60)
    at org.neo4j.helpers.collection.PrefetchingIterator.hasNext(PrefetchingIterator.java:46)
    at org.neo4j.helpers.collection.PrefetchingIterator.next(PrefetchingIterator.java:75)
    at org.neo4j.kernel.impl.traversal.OldTraverserWrapper$TraverserImpl.next(OldTraverserWrapper.java:86)
    at org.neo4j.kernel.impl.traversal.OldTraverserWrapper$TraverserImpl.next(OldTraverserWrapper.java:47)
    at org.neo4j.gis.spatial.filter.SearchRecords.next(SearchRecords.java:53)
    at org.neo4j.gis.spatial.filter.SearchRecords.next(SearchRecords.java:29)
    at org.neo4j.gis.spatial.pipes.GeoPipeline$1.next(GeoPipeline.java:134)
    at org.neo4j.gis.spatial.pipes.GeoPipeline$1.next(GeoPipeline.java:126)
    at org.neo4j.gis.spatial.pipes.impl.LastElementIterator.next(LastElementIterator.java:19)
    at org.neo4j.gis.spatial.pipes.impl.IdentityPipe.processNextStart(IdentityPipe.java:18)
    at org.neo4j.gis.spatial.pipes.impl.AbstractPipe.next(AbstractPipe.java:72)
    at org.neo4j.gis.spatial.pipes.AbstractGeoPipe.processNextStart(AbstractGeoPipe.java:49)
    at org.neo4j.gis.spatial.pipes.AbstractGeoPipe.processNextStart(AbstractGeoPipe.java:31)
    at org.neo4j.gis.spatial.pipes.impl.AbstractPipe.next(AbstractPipe.java:72)
    at org.neo4j.gis.spatial.pipes.impl.Pipeline.next(Pipeline.java:113)
    at org.neo4j.gis.spatial.pipes.GeoPipeline.toNodeList(GeoPipeline.java:1015)
   
Cheers,
Alireza

Michael Hunger

unread,
Aug 8, 2015, 5:48:24 PM8/8/15
to ne...@googlegroups.com
It seems you created the layer with a WKB (well known binary) representation config

but now your location properties are not decodable as WKB because they are double's ?

Michael

Perhaps you can share a test that reproduces the issue?

Alireza Rezaei Mahdiraji

unread,
Aug 8, 2015, 5:57:27 PM8/8/15
to Neo4j

I used Coordinate coord = new Coordinate(0.0d, 0.0d); as a test location which is required by
startNearestNeighborLatLonSear (see my first post).
Is that enough?

Alireza
...

Alireza Rezaei Mahdiraji

unread,
Aug 8, 2015, 6:02:39 PM8/8/15
to Neo4j

Let me ask you a design kind of question: the nodes in my graph could have various geometry: point, line, or polygon.
I used the following layer definition (but I am not sure that is the best way to do it)"

EditableLayer runningLayer = (EditableLayer)
                graphDBSpatial.getOrCreateLayer(layerName,
                    WKBGeometryEncoder.class,
                        EditableLayerImpl.class,
                            geomEncoderConfig);

I appreciate if you comment on this. 

Alireza
...

Michael Hunger

unread,
Aug 8, 2015, 6:04:54 PM8/8/15
to ne...@googlegroups.com
The error means that it tries to decode a location / geometry using a binary decoder but that fails as the property is set to double instead.

Michael

Craig Taverner

unread,
Aug 10, 2015, 5:09:21 AM8/10/15
to ne...@googlegroups.com
Hi Alireza,

I wrote some test code using your layer creation and neighbour search code that you pasted, and it works fine. So what I think has happened is that you have somehow added nodes with a different layer config to the same index that you are now using for WKB. Perhaps the nodes used to be points in a simple point layer, and now you changed to a WKB layer, it is no longer compatible.

I can make a few suggestions:
  • Make sure your nodes were added using the layer.add(Geometry) method. If you used layer.add(Node) then it is your responsibility to make sure the node conforms to the same layer config that you are planning to use. For example, do not add a simple point node (with lat/lon attributes) to a WKT layer, or you are likely to create this kind of issue.
  • Since you are working with points, can I suggest you not use the WKB layer config, but rather use the SimplePointLayer, as created by SpatialGraphDatabase.createSimplePointLayer(name) or SpatialGraphDatabase.createSimplePointLayer(name,xProp,yProp)
Regards, Craig

--

Alireza Rezaei Mahdiraji

unread,
Aug 12, 2015, 10:01:26 AM8/12/15
to Neo4j

Hi Craig,

As always thanks for your nice reply.

I understood the problem but not the solution yet. The fact is I have points, lines, and polygons as geometries.
Four main queries which I have are as follows:

1- given coordinates of an arbitrary point (i.e., not a node in the graph) find the polygon node which enclose it

2- given a point node find all other nodes which are withing distance r of it.

3- given a point node find all k nearest neighbors point node of it

4- given two polygon determines if they intersect and perhaps find the size of intersection

I defined my layer as follows (I tried with WKB too):


        EditableLayer runningLayer = (EditableLayer) graphDBSpatial.getOrCreateLayer(layerName,
                    WKTGeometryEncoder.class,
                        EditableLayerImpl.class,
                            "x:y:z");

Then I create my nodes as follows:

// point node
Point p = runningLayer.getGeometryFactory().createPoint(coord);
        SpatialDatabaseRecord v = runningLayer.add(p);

// edge node
LineString lineString = runningLayer.getGeometryFactory().createLineString(coord);
        SpatialDatabaseRecord e = runningLayer.add(lineString);

// polygon node
Polygon poly = runningLayer.getGeometryFactory().createPolygon(coordinates);
        SpatialDatabaseRecord tc = runningLayer.add(poly);

Based on what you said I should have a separate layer for point, right? If the answer is yes, then while querying I should load two layers
based on which of the queries above is requested (WKT layer for queries 1 and 4 and Point layer for 2 and 3), is that correct ?

Cheers,
Alireza

Craig Taverner

unread,
Aug 12, 2015, 10:36:35 AM8/12/15
to ne...@googlegroups.com
Hi Alireza,

Since you have three different geometry types, you are correct to use WKT (or WKB) for the layer. This layer can handle all three types. You do not need a separate layer for points. The only reason I suggested making a points-only layer was that I thought perhaps you only stored points. But since you store all types, rather have a layer that can handle all.

The code you have above looks fine and similar to the test code I made. So it should work fine. The error you had earlier looked like you had tried to manually create node geometries and add the nodes to the layer, instead of adding the geometry to the layer.

One thing I find a little strange above is that you have chosen to use an encoder config with three fields "x:y:z". But the WKB and WKT encoders only understand two. The first is the geometry property name (you chose "x" to hold the geometry in the node), and the second is the bbox property. I think it a little confusing to store a whole polygon in "x" and to store the envelope(bbox) in "y". I'm guessing this is not what you intended to do? I advise you rather pass a single string with no ':' separators, like 'my_geom'. Better yet, leave it empty and get the default value. In fact you can leave off all fields but the layer name, if you use the method getOrCreateEditableLayer(name).

Here is a section of the test code I tried, which worked, and adds a Point and LineString to the layer:

    SpatialDatabaseService db = new SpatialDatabaseService( graphDb() );
String layerName = "myLayer";
String geomPropertyName = "my_geom";
EditableLayer layer = (EditableLayer) db.getOrCreateLayer( layerName,
WKBGeometryEncoder.class,
EditableLayerImpl.class,
geomPropertyName );
GeometryFactory gf = layer.getGeometryFactory();
SpatialDatabaseRecord record = layer.add( gf.createPoint( new Coordinate( 15.25, 56.15 ) ) );
LinearRing ring = gf.createLinearRing( new Coordinate[]{
new Coordinate( 15.3, 56.2 ),
new Coordinate( 15.4, 56.2 ),
new Coordinate( 15.4, 56.3 ),
new Coordinate( 15.3, 56.3 ),
new Coordinate( 15.3, 56.2 )
} );
Polygon polygon = gf.createPolygon( ring, null );
record = layer.add( polygon );
You can use WKB or WKT for this layer. Note that if you created a layer with simply:
db.getOrCreateEditableLayer( layerName );
Then you get a WKB layer with default configs.

Regards, Craig

Alireza Rezaei Mahdiraji

unread,
Aug 12, 2015, 11:32:48 AM8/12/15
to Neo4j

Very well explained, thanks,

However, one problem with one layer solution is that when I am trying Q2 and Q3 it
returns also non-point nodes (edge and polygons) which are not part of the result.
So I think it might be better for me to have two layers. Is there any performance cost on having several layers?

Using the two layer approach for query Q2 and Q3 I am not getting the desired results. For instance for query Q2:

Node s = dbInstance.findNode(dbLabel, "cid", Integer.parseInt(cellId));
Geometry geometry = layer.getGeometryEncoder().decodeGeometry(s);
       
List<SpatialDatabaseRecord> snodes = GeoPipeline.
      startNearestNeighborLatLonSearch(layer, geometry.getCoordinate(), 1.0).toSpatialDatabaseRecordList();

where the coordinates of node s are (0.0, 0.0). It returns only the node itself. Looking at the source,
it seems startNearestNeighborLatLonSearch builds a window which is much more smaller. Should I
build my own window and pass to startNearestNeighborLatLonSearch instead of last param ?

Similar problem with startNearestNeighborSearch when looking for K neighbors.

Cheers,
Thanks,
Alireza

Craig Taverner

unread,
Aug 12, 2015, 3:25:52 PM8/12/15
to ne...@googlegroups.com
Hi Alireza,

Having two layers is no problem, if you don't mind making and using two. It could even be faster to query, because the indexes will be smaller.

You should certainly try the alternative methods for searching for neighbours, either the one that takes a suggested limit of results to return, or the one where you provide your own search envelope. Each will work a little different from the others, and you may find one works best for you.

If you know your domain best, you might find that building your own search window is the best because you will know things the code cannot.

Regards, Craig

Alireza Rezaei Mahdiraji

unread,
Aug 13, 2015, 12:28:01 PM8/13/15
to Neo4j

Yeah, I think I should do it myself. The case for knn seems more challenging ...

Thanks,
Alireza
...
Reply all
Reply to author
Forward
0 new messages