Hot questions for Using Neo4j in neo4j spatial

Top Java Programmings / Neo4j / neo4j spatial

Question:

i'm trying to add a lon lat point to a node. i was unable to find any doc regarding which java class should be used.

Here is what i have:

@NodeEntity
public class Coordination {

    @Id
    @GeneratedValue
    private Long id;

    @Index
    private Value point;


    private Double lon;
    private Double lat;
    @Relationship(type = "GEO_LOCATION", direction = Relationship.INCOMING)
    private List<GeoLocation> geoLocations;

    public Coordination(Double lon, Double lat) {
        Value point = new PointValue(new InternalPoint2D(4326, lon, lat));
        this.lon = lon;
        this.lat = lat;
    }
}

Value class is not working for me. what do i miss?


Answer:

Using a CompositeAttributeConverter it is possible to define your own class to store lat and lon coordinates. However, you can also use the built-in Point and corresponding Distance classes defined in Spring Data Commons.

Here's an example from the test cases in Spring Data Neo4j:

public class Restaurant implements Comparable<Restaurant> {

    @Id @GeneratedValue private Long id;
    private String name;
    @Convert(PointConverter.class) private Point location; //Encapsulates lat/lon 
    private int zip;
    private double score;
    private String description;
    private boolean halal;

You can then define methods such as:

import org.springframework.data.geo.Point;
import org.springframework.data.neo4j.conversion.PointConverter;

public interface RestaurantRepository extends Neo4jRepository<Restaurant, Long> {

    List<Restaurant> findByNameAndLocationNear(String name, Distance distance, Point point);

    List<Restaurant> findByLocationNearAndName(Distance distance, Point point, String name);
}

The finder method will generate CYPHER that passes the following arguments to a distance function:

  • The lat and lon properties defined on your node
  • The at and lon arguments passed in as an argument to the finder method.

Is this what you were looking for? If yes great! If not, could you please clarify your question.

Question:

I know there is a similar question to this (to question: Neo4j Spatial: can't run spatial), however that question seems to be solved when installing dependencies. I think that is not the solution to my case.

After installing Neo4j and installing maven

$ brew install neo4j
$ brew install maven

making a directory called spatial and cloning neo4j-spatial to this folder.

$ git clone https://github.com/neo4j-contrib/spatial.git

Then i tried to maven install this git clone.

/spatial$ mvn install

After a lot of test it returns a "Build failure"

Results :

Failed tests: 
  ProgressLoggingListenerTest.testProgressLoggingListnerWithAllLogs:38->testProgressLoggingListenerWithSpecifiedWaits:62 
Argument(s) are different! Wanted:
forwardingPrintStream.println(
    "100.00 (10/10) - Completed test"
);
-> at org.neo4j.gis.spatial.ProgressLoggingListenerTest.testProgressLoggingListenerWithSpecifiedWaits(ProgressLoggingListenerTest.java:62)
Actual invocation has different arguments:
forwardingPrintStream.println(
    "10,00 (1/10) - Running test"
);
-> at org.neo4j.gis.spatial.rtree.ProgressLoggingListener.lambda$new$1(ProgressLoggingListener.java:45)

  ProgressLoggingListenerTest.testProgressLoggingListnerWithOnlyStartAndEnd:46->testProgressLoggingListenerWithSpecifiedWaits:62 
Argument(s) are different! Wanted:
forwardingPrintStream.println(
    "100.00 (10/10) - Completed test"
);
-> at org.neo4j.gis.spatial.ProgressLoggingListenerTest.testProgressLoggingListenerWithSpecifiedWaits(ProgressLoggingListenerTest.java:62)
Actual invocation has different arguments:
forwardingPrintStream.println(
    "10,00 (1/10) - Running test"
);
-> at org.neo4j.gis.spatial.rtree.ProgressLoggingListener.lambda$new$1(ProgressLoggingListener.java:45)


Tests run: 146, Failures: 2, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 10:34 min
[INFO] Finished at: 2016-09-23T15:55:35+02:00
[INFO] Final Memory: 44M/558M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.18.1:test (default-test) on project neo4j-spatial: There are test failures.
[ERROR] 
[ERROR] Please refer to /Volumes/Macintosh HD/Users/Tom/spatial/target/surefire-reports for the individual test results.
[ERROR] -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

In my queeste to solve this "Build failure" I discovered that most maven install errors are due to dependencies. However these error messages do not indicate any missing dependencies?

I tried using mvn verify however this just seems to try to build the plugin again returning the same Build failure.

/spatial$ mvn verify 

Two questions; - Am I missing dependencies or is the problem in something else? - If I am missing dependencies, what are they and how to install them?

Thanks in advance!


Answer:

The tests depend on the locale of the build environment as it checks the result of number formatting with decimal number, expecting a point as the decimal separator:

"100.00 (10/10) - Completed test"

Your locale uses the comma as the decimal separator, based on the actual value reported:

"10,00 (1/10) - Running test"

You have 2 options:

  • Build the project without running the tests:

    mvn install -Dmaven.test.skip
    
  • Change the locale for the build:

    LANG=C mvn install
    

    or

    LANG=en_US mvn install
    

Question:

Using the Neo4j Spatial core java api, I have been able to put together code which allows me to lookup nodes within a specific distance from a given point however, I would like to be able to include nodes based on their catchment radius.

For example, if I am located at any given point which pizza companies in my local area or further afield could deliver to me (given their own delivery radius)

Any ideas on how this could be achieved with Neo4j Spatial?


Answer:

Instead of modelling your Pizza companies as simply points on a map could you model their delivery radius as a related geometry shape? This would give you greater control over the delivery shape as well (not delivering to an island for example).

If you model the deliver area as a WKT Polygon, you can then perform a search in the form:

START loc = node:idx_bounding_location(withinDistance:[<lat>,<lon>,0.0])
MATCH (pz:Pizza:Company)-[:DELIVERY_AREA]->loc
RETURN pz

In this query the lat and lon values are the location of the person requiring pizza delivery.

Question:

I have seen a few posts here on stack that show how to create a simplePointLayer. However, the process is failing for me. I am using Neo4J version 3.0.2 and the spatial plugin version 3.0.2.

I have been here, here, and here.

Each of these pages contains the same set of instructions for creating a SimplePointLayer, as shown below.

This step works just fine for me:

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" 
}

I'm not sure where to see a listing of layers, but the response is 200, so I'm assuming everything works as expected here.

The following step is where I am stuck:

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" 
    } 
}

I have the json above in a file tmp.json and I run

cat tmp.json | http :7474/db/data/index/node

This generates the following message:

HTTP/1.1 400 Bad Request
Access-Control-Allow-Origin: *
Content-Length: 6887
Content-Type: application/json; charset=UTF-8
Date: Wed, 06 Jul 2016 18:14:18 GMT
Server: Jetty(9.2.9.v20150224)

{
    "errors": [
        {
            "code": "Neo.DatabaseError.General.UnknownError", 
            "message": "No index provider 'spatial' found. Maybe the intended provider (or one more of its dependencies) aren't on the classpath or it failed to load.", 
            "stackTrace": "java.lang.IllegalArgumentException: No index provider 'spatial' found. Maybe the intended provider (or one more of its dependencies) aren't on the classpath or it failed to load.\n\tat org.neo4j.kernel.NeoStoreDataSource$1.apply(NeoStoreDataSource.java:386)\n\tat org.neo4j.kernel.NeoStoreDataSource$1.apply(NeoStoreDataSource.java:378)\n\tat org.neo4j.kernel.impl.index.LegacyIndexStore.findIndexConfig(LegacyIndexStore.java:105)\n\tat org.neo4j.kernel.impl.index.LegacyIndexStore.getOrCreateIndexConfig(LegacyIndexStore.java:171)\n\tat org.neo4j.kernel.impl.index.LegacyIndexStore.getOrCreateNodeIndexConfig(LegacyIndexStore.java:64)\n\tat org.neo4j.kernel.impl.api.StateHandlingStatementOperations.nodeLegacyIndexCreateLazily(StateHandlingStatementOperations.java:1475)\n\tat org.neo4j.kernel.impl.api.OperationsFacade.nodeLegacyIndexCreateLazily(OperationsFacade.java:1195)\n\tat org.neo4j.kernel.impl.coreapi.IndexProviderImpl.getOrCreateNodeIndex(IndexProviderImpl.java:52)\n\tat org.neo4j.kernel.impl.coreapi.IndexManagerImpl.forNodes(IndexManagerImpl.java:81)\n\tat org.neo4j.server.rest.web.DatabaseActions.createNodeIndex(DatabaseActions.java:381)\n\tat org.neo4j.server.rest.web.RestfulGraphDatabase.jsonCreateNodeIndex(RestfulGraphDatabase.java:845)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n\tat java.lang.reflect.Method.invoke(Method.java:498)\n\tat com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)\n\tat com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:205)\n\tat com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)\n\tat org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:144)\n\tat com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:302)\n\tat com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)\n\tat com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)\n\tat com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)\n\tat com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)\n\tat com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1542)\n\tat com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1473)\n\tat com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1419)\n\tat com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1409)\n\tat com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:409)\n\tat com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:558)\n\tat com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:733)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:790)\n\tat org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:808)\n\tat org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669)\n\tat org.neo4j.server.rest.web.CollectUserAgentFilter.doFilter(CollectUserAgentFilter.java:69)\n\tat org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)\n\tat org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)\n\tat org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:221)\n\tat org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)\n\tat org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)\n\tat org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)\n\tat org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)\n\tat org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)\n\tat org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:52)\n\tat org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)\n\tat org.eclipse.jetty.server.Server.handle(Server.java:497)\n\tat org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310)\n\tat org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)\n\tat org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540)\n\tat org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)\n\tat org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)\n\tat java.lang.Thread.run(Thread.java:745)\n"
        }
    ], 
    "exception": "IllegalArgumentException", 
    "fullname": "java.lang.IllegalArgumentException", 
    "message": "No index provider 'spatial' found. Maybe the intended provider (or one more of its dependencies) aren't on the classpath or it failed to load.", 
    "stackTrace": [
        "org.neo4j.kernel.NeoStoreDataSource$1.apply(NeoStoreDataSource.java:386)", 
        "org.neo4j.kernel.NeoStoreDataSource$1.apply(NeoStoreDataSource.java:378)", 
        "org.neo4j.kernel.impl.index.LegacyIndexStore.findIndexConfig(LegacyIndexStore.java:105)", 
        "org.neo4j.kernel.impl.index.LegacyIndexStore.getOrCreateIndexConfig(LegacyIndexStore.java:171)", 
        "org.neo4j.kernel.impl.index.LegacyIndexStore.getOrCreateNodeIndexConfig(LegacyIndexStore.java:64)", 
        "org.neo4j.kernel.impl.api.StateHandlingStatementOperations.nodeLegacyIndexCreateLazily(StateHandlingStatementOperations.java:1475)", 
        "org.neo4j.kernel.impl.api.OperationsFacade.nodeLegacyIndexCreateLazily(OperationsFacade.java:1195)", 
        "org.neo4j.kernel.impl.coreapi.IndexProviderImpl.getOrCreateNodeIndex(IndexProviderImpl.java:52)", 
        "org.neo4j.kernel.impl.coreapi.IndexManagerImpl.forNodes(IndexManagerImpl.java:81)", 
        "org.neo4j.server.rest.web.DatabaseActions.createNodeIndex(DatabaseActions.java:381)", 
        "org.neo4j.server.rest.web.RestfulGraphDatabase.jsonCreateNodeIndex(RestfulGraphDatabase.java:845)", 
        "java.lang.reflect.Method.invoke(Method.java:498)", 
        "org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:144)", 
        "org.neo4j.server.rest.web.CollectUserAgentFilter.doFilter(CollectUserAgentFilter.java:69)", 
        "java.lang.Thread.run(Thread.java:745)"
    ]
}

I'm not sure where to go from here. I am assuming the 'provider' is the plugin. I am not a JAVA person, so I'm not sure how to deal with classpaths. Has anyone encountered this error before \ know how to deal with this problem?


Answer:

The spatial library is in a bit of flux at the moment with the introduction of user defined procedures in Neo4j 3.0. Specifically:

  1. Procedures are becoming the recommended way to interact with spatial, and

  2. The index provider has been removed from the spatial library (causing the error you encountered)

With procedures you now have access to spatial functionality from Cypher:

Create layer

CALL spatial.addPointLayer('cities');

Add all cities to the layer

MATCH (c:City)
WITH collect(c) AS cities
CALL spatial.addNodes('cities',cities) YIELD node
RETURN count(*)

Find cities within distance

MATCH (c:City {name:"Berlin"}) WITH c
CALL spatial.distance('cities', c , 200) YIELD node, distance
RETURN node.name AS name, round(distance) AS dist

See this for more info.