Depth in custom Cypher queries with OGM always 0? - neo4j

I'm currently evaluating OGM / Spring Data Neo4j for a use case and came upon the following problem:
When executing a custom Cypher query either via Spring Data #Query annotation or directly via the Neo4j Session, the result contains only the nodes directly queried for and not the related nodes (relationships are null in the resulting node objects). I.e. the depth for these queries seems to be 0 and not 1, as I would have expected from the docs.
How can I execute a custom Cypher query via OGM or Spring Data Neo4j that has depth 1?

The default depth 1 refers to findOne/findAll/.. methods from the repository and derived finders.
This is what the documentation says about custom queries:
In the current version, custom queries do not support paging, sorting or a custom depth. In addition, it does not support mapping a path to domain entities, as such, a path should not be returned from a Cypher query. Instead, return nodes and relationships to have them mapped to domain entities.
http://docs.spring.io/spring-data/data-neo4j/docs/current/reference/html/#reference:session:loading-entities:cypher-queries
For example when you have a query
MATCH (n:MyLabel)-[r]-(n2)
WHERE ... // some condition
RETURN n,r,n2
list all nodes/relationships you want to map to your objects in the RETURN clause.

Related

Neo4j OGM Filter query against array

I'm trying to build a small property searching system. I'm using spring boot with a neo4j database and I'm trying to query from the neo4j database using filters becasue i need the querying to be dynamic too. In my use case properties has features such as electricity, tap water, tilled roof, etc. Property & Feature are nodes, Feature node has an attribtue named 'key', a Property node is linked to many Feature nodes by rich relationships typed HAS_FEATURE, what i want to do is query properties for a given array of feature keys using Filters. Follwing is code,
featureKeys is a java List here,
filter = new Filter("key", ComparisonOperator.IN, featureKeys);
filter.setRelationshipType("HAS_FEATURE");
filter.setNestedPropertyName("hasFeatures");
filter.setNestedPropertyType(Feature.class);
filters.add(filter);
SESSION.loadAll(Property.class, filters, new Pagination(pageNumber, pageSize));
The problem is i want only the properties that related to all the given features keys to be returned, but even the properties that is related to one element of the given feature key list is also returned. What do i need to do to query only the properties that are linked to all the given list elements, i can change the rich relationship to a normal relationship if needed.

Neo4j OGM | Adhoc Cypher Queries

I'm trying to run adhoc cyphers (where the results don't necessarily always map to the domain entity object).
I'm using the
session.query(cypher)
API for that.
Not sure what should be the output type?
An example is:
I've got Event, Flight modelled as first class entities and they are related via "HAS_FLIGHT"
I run this Cypher Query:
session.query("MATCH (p:Event)-[hf:HAS_FLIGHT]->(f:Flight)
RETURN p,hf,f,count(p) AS totalEvents")
Interestingly I only get returned an arraylist of the value counts (ie the totalEvents).
How can I get all the values mentioned in the RETURN clause in a map or something and I can build the domain objects after the retrieval.
There is no need to return a map if you just want to construct your domain objects from a query.
session.query("MATCH p=(:Event)-[:HAS_FLIGHT]->(:Flight) return nodes(p), rels(p)")
This will return an Iterable of all events having one or more flights.
Which session do you use? When I'm looking at org.neo4j.ogm.session.Session I can only see query overloads with more than one argument.
Two of them return a org.neo4j.ogm.model.Result object that contains a map for each result row. The map holds the value for each of the items in the return clause.

Neo4j 2.2: Cypher Spatial request with other parameters returns Index does not exist

I'm using Neo4j to find Users who are in a 50 km radius and who are available on specific days.
This question is similar to this other question but Indexes have changed since Neo4J 2.0 so the solution does not work.
I use Neo4j 2.2.1, Neo4j-spatial 0.14 and py2neo / py2neo-spatial to interact with the graph.
To add user geometries to the graph I use:
def create_geo_node(graph, node, layer_name, name, latitude, longitude):
spatial = Spatial(graph)
layer = spatial.create_layer(layer_name)
node_id = node._id
shape = parse_lat_long(latitude, longitude)
spatial.create_geometry(geometry_name=name, wkt_string=shape.wkt, layer_name="Users", node_id=node_id)
..which creates the spatial nodes as wanted.
I then would like to query the graph by doing:
START user=node:Users('withinDistance:[4.8,45.8,100]')
MATCH period=(start_date:Date)-[:NEXT_DAY*]->(end_date:Date)
WHERE start_date.date="2014-03-03" AND end_date.date="2014-03-04"
UNWIND nodes(period) as nodes_in_period
OPTIONAL MATCH (nodes_in_period)<-[a:AVAILABLE]-(user:User)
RETURN user.uuid, count(a)/count(nodes(period))
but the query returns:
Index `Users` does not exist
Is seems that the py2neo spatial.create_layer(..) creates the layer but not the Index (but should it? ..as Indexes are now a "Legacy" of Neo4j 1.*)
Using py2neo spatial find_within_distance works but since it uses the REST api I cannot make mixed requests which take into account other parameters
From what I understand, START is deprecated since Neo4j 2.0 but I am unable to find the correct Cypher query for withinDistance in Neo4j 2.2
Thank you in advance,
Benjamin
create_layer creates a "spatial" index which is different to Neo's Indexes. It actually creates a graph which models some bounding boxes for you so that you can then carry out spatial queries over your data. You don't need to reference this index directly. Think of it more like a GIS layer.
You can inspect your graph and dig out the Node attributes you need to write your own cypher query.
But you could also use the py2neo spatial API find_within_distance
http://py2neo.org/2.0/ext/spatial.html#py2neo.ext.spatial.plugin.Spatial.find_within_distance
Hope this helps.
I think that those links can be usefull :
* Neo4j Spatial 'WithinDistance' Cypher query returns empty while REST call returns data
* https://github.com/neo4j-contrib/spatial/issues/106
But the problem is not that you haven't got any result, but an error on the index ... that's why I'm perplex.
Can you test neo4j spatial directly with some REST query (to create layer & spatial node) to see what happen ?
Otherwise, for your question about cypher start condition, you just have to put this condition into the match one like this :
MATCH
user=node:Users('withinDistance:[4.8,45.8,100]'),
period=(start_date:Date {date:'2014-03-03'})-[:NEXT_DAY*]->(end_date:Date {date:'2014-03-04'})
UNWIND nodes(period) as nodes_in_period
OPTIONAL MATCH (nodes_in_period)<-[a:AVAILABLE]-(user:User)
RETURN user.uuid, count(a)/count(nodes(period))

Cypher query to find a node based on a regexp on a property

I have a Neo4J database mapped with COMPANY as nodes and RELATED as edges. COMPANY has a CODE property. I want to query the database and get the first node that matches the regexp COMPANY.CODE =~ '12345678.*', i.e., a COMPANY whose first 8 letters of CODE is equal a given string literal.
After several attempts, the best I could come up with was the following query:
START p=node(*) where p.CODE =~ '12345678.*' RETURN p;
The result is the following exception:
org.neo4j.cypher.EntityNotFoundException:
The property 'CODE' does not exist on Node[0]
It looks like Node[0] is a special kind of node in the database, that obviously doesn't have my CODE property. So, my query is failing because I'm not choosing the appropriate type of node to query upon. But I couldn't figure out how to specify the type of node to query on.
What's the query that returns what I want?
I think I need an index on CODE to run this query, but I'd like to know whether there's a query that can do the job without using such an index.
Note: I'm using Neo4J version 1.9.2. Should I upgrade to 2.0?
You can avoid the exception by checking for the existence of the property,
START p=node(*)
WHERE HAS(p.CODE) AND p.CODE =~ '12345678.*'
RETURN p;
You don't need an index for the query to work, but an index may increase performance. If you don't want indices there are several other options. If you keep working with Neo4j 1.9.x you may group all nodes representing companies under one or more sorting nodes. When you query for company nodes you can then retrieve them from their sorting node and filter on their properties. You can partition your graph by grouping companies with a certain range of values for .code under one sorting node, and a different range under another; and you can extend this partitioning as needed if your graph grows.
If you upgrade to 2.0 (note: not released yet, so not suitable for production) you can benefit from labels. You can then assign a Company label to all those nodes and this label can maintain it's own index and uniqueness constraints.
The zero node, called 'reference node', will not remain in future versions of Neo4j.

Neo4j Spatial- two nodes created for every spatially indexed node

I am using Neo4j 1.8.2 with Neo4j Spatial 0.9 for 1.8.2 (http://m2.neo4j.org/content/repositories/releases/org/neo4j/neo4j-spatial/0.9-neo4j-1.8.2/)
Followed the example code from here http://architects.dzone.com/articles/neo4jcypher-finding-football with one change- instead of SpatialIndexProvider.SIMPLE_WKT_CONFIG, I used SpatialIndexProvider.SIMPLE_POINT_CONFIG_WKT
Everything works fine until you execute the following query:
START n=node:stadiumsLocation('withinDistance:[53.489271,-2.246704, 5.0]')
RETURN n.name, n.wkt;
n.name is null. When I explored the graph, I found this data:
Node[80]{lon:-2.20024,lat:53.483,id:79,gtype:1,bbox:-2.20024,53.483,-2.20024,53.483]}
Node[168]{lon:-2.29139,lat:53.4631,id:167,gtype:1,bbox:-2.29139,53.4631,-2.29139,53.4631]}
For Node 80 returned, it looks like this is the node created for the spatial record, which contains a property id:79. Node 79 is the actual stadium record from the example.
As per the source of IndexProviderTest, the comments
//We not longer need this as the node we get back already a 'Real' node
// Node node = db.getNodeById( (Long) spatialRecord.getProperty( "id" ) );
seem to indicate that this feature isn't available in the version I am using.
My question is, what is the recommended way to use withinDistance with other match conditions? There are a couple of other conditions to be fulfilled but I can't seem to get a handle on the actual node to actually match them.
Should I explicitly create relations? Not use Cypher and use the core API to do a traversal? Split the queries?
Two options:
a) Use GeoPipline.startNearestNeighborLatLonSearch to get a starting set of nodes, supply to subsequent Cypher query to do matching/filtering on other properties
b) Since my lat/longs are common across many entities [using centroid of an area], I can create a relation from the spatial node to all entities that are located in that area and then use one Cypher query such as:
START n=node:stadiumsLocation('withinDistance:[53.489271,-2.246704, 5.0]')
MATCH (n)<-[:LOCATED_IN]-(something)
WHERE something.someProp=5
RETURN something
As advised by Peter, went with option b.
Note though, there is no way to get the spatially indexed node back so that you can create relations from it. Had to do a withinDistance query for 0.0 distance.
can you execute the enhanced testcase I did at https://github.com/neo4j/spatial/blob/2803093d544f56d7dfe8f1d122e049fa73489d8a/src/test/java/org/neo4j/gis/spatial/IndexProviderTest.java#L199 ? It shows how to find a location, and traverse with cypher to the next node.

Resources