3
votes

I am new to Neo4J and I am trying to build a proof of concept for High Availability spatial temporal based querying.

I have a setup with 2 standalone Neo4J Enterprise servers and a single Java application running with an embedded HA Neo4J server.

Everything was simple to setup and basic queries are easy to setup and efficient. Additionally performing the queries derived from the Neo4J SpatialRepository work as expected.

What I am struggling to understand is how to use SDN to make a spatial query in combination with any other where clauses. As a trivial example how could I write find all places User called X has been within Y miles of lat/lon. Because the SpatialRepository is not part of the regular Spring Repository class tree I do not believe that there are any naming conventions that I can use, is the intention that I perform the spatial query and then filter the results?

I have traced the code through to a LegacyIndexSearcher (which has a name that scares me!) and cannot see any mechanism for extending the search. I have also had a look at the IndexProviderTest on GitHub which could provide a manual mechanism for performing the query against the index, except that I think there may be two indexes in play.

It might be helpful if I understood how to construct a Cypher query that I could use within an @Query annotation. Whilst I have been able to use the console to perform a simple REST query using:

  :POST /db/data/ext/SpatialPlugin/graphdb/findGeometriesWithinDistance
  {
    "layer":"location", 
    "pointX":0.0, 
    "pointY":51.526256, 
    "distanceInKm":100 
  }

This does not work:

  start n=node:location('withinDistance:[51.526256,0.0,100.0]') return n;

The error is:

  Index `location` does not exist
  Neo.ClientError.Schema.NoSuchIndex

The index was (possibly naively) created using Spring:

  @Indexed(indexType = IndexType.POINT, indexName = "location")
  String wkt;

If I run index --indexes in the console I can see that there is no index named location, but that there is one named location__neo4j-spatial__LayerNodeIndex__internal__spatialNodeLookup__.

Am I required to create the Index manually? If so, could someone point me in the direction of the documentation and I'll get on with it.

Assuming that it is just ignorance that has stopped me getting the simple Cypher query to run, is it as simple as adding a regular Cypher WHERE clause to the query to perform the combination of Spatial and property based querying?

Added more index detail
Having run :GET /db/data/index/node/ from the console I could see two possibly useful indexes (other indexes removed):

{
  "location__neo4j-spatial__LayerNodeIndex__internal__spatialNodeLookup__": {
    "template": "/db/data/index/node/location__neo4j-spatial__LayerNodeIndex__internal__spatialNodeLookup__/{key}/{value}",
    "provider": "lucene",
    "type": "exact"
  },
  "GeoTemporalThing": {
    "template": "/db/data/index/node/GeoTemporalThing/{key}/{value}",
    "provider": "lucene",
    "type": "exact"
  }
}

So perhaps this should is the correct format for the query I was trying:

start n=node:GeoTemporalThing('withinDistance:[51.526256,0.0,100.0]') return n;

But that gives me this error (which I am now Googling)

org.apache.lucene.queryParser.ParseException: Cannot parse 'withinDistance:[51.526256,0.0,100.0]': Encountered " "]" "] "" at line 1, column 35.
Was expecting one of:
    "TO" ...
     ...
     ...

Update
Having decided that my index didn't exist and that it should I used the REST interface to create an index with the name that I expected SDN to create like this:

:POST /db/data/index/node
{
  "name" : "location",
  "config" : {
    "provider" : "spatial",
    "geometry_type" : "point",
    "wkt" : "wkt"
  }
}

And, now everything seems to work just fine. So, my question is, should I have to create that index manually? If I look at the code in org.springframework.data.neo4j.support.index.IndexType it looks as if it should use exactly the settings that I used above but it had only created the long named Lucene Index:

public enum IndexType
{   
    @Deprecated
    SIMPLE   { public Map getConfig() { return LuceneIndexImplementation.EXACT_CONFIG; } },
    LABEL    { public Map getConfig() { return null; }  public boolean isLabelBased() { return true; }},
    FULLTEXT { public Map getConfig() { return LuceneIndexImplementation.FULLTEXT_CONFIG; } },
    POINT    { public Map getConfig() { return MapUtil.stringMap(
                      IndexManager.PROVIDER, "spatial", "geometry_type" , "point","wkt","wkt") ; } }

    ;

    public abstract MapgetConfig();

    public boolean isLabelBased() { return false; }
}

I did clear down the system and the behaviour was the same, is there a step I have missed?

Software details:

Java:
neo4j 2.0.1
neo4j-ha 2.0.1
neo4j-spatial 0.12-neo4j-2.0.1
spring-data-neo4j 3.0.0.RELEASE

Standalone Servers:
neo4j-enterprise-2.0.1
neo4j-spatial-0.12-neo4j-2.0.1-server-plugin

1

1 Answers

1
votes

I'm not sure if this is a bug in Spring Data when setting up the index, but manually creating the index using the REST index worked:

:POST /db/data/index/node
{
  "name" : "location",
  "config" : {
    "provider" : "spatial",
    "geometry_type" : "point",
    "wkt" : "wkt"
  }
}

I can now perform queries with minimal effort using cypher in an @Query annotation (more parameters coming obviously):

@Query(value = "start n=node:location('withinDistance:[51.526256,0.0,100.0]') MATCH user-[wa:WAS_HERE]-n WHERE wa.ts > {ts} return user"
Page findByTimeAtLocation(@Param("ts") long ts);