Neo4j Manual Index on Relationship Properties - neo4j

I'm going to try in my application Neo4j Manual Index on Relationship Properties in order to fix the performance issue I faced Neo4j Cypher query performance optimization
I have a few question which is not clear to me from the official Neo4j documentation:
MATCH (:Flight)-[r:DESTINATION]->(:Airport)
CALL apoc.index.addRelationship(r,['taxi_time'])
RETURN count(*)
The statement will create the relationship index with the same name as
relationship-type, in this case DESTINATION and add the relationship
by its properties to the index.
When do I need to create this relationship index? It should be done once(let's say at the application startup) or do I need to invoke this APOC function each time new -[r:DESTINATION]-> relationship is added between Flight and Airport nodes?
In case of existing -[r:DESTINATION]-> relationship update, how to update this information in the appropriate manual index?
In case of deleting some of Flight or Airport node - do I need to manually find and remove appropriate -[r:DESTINATION]-> relationships from the manual index or it will be done automatically by APOC and Neo4j?
In case of Spring Data Neo4j project - how to properly execute queries that contain APOC functions? For example, I want to call apoc.index.addRelationship in order to create the manual index for the relationship properties. Can I use org.neo4j.ogm.session.Session.query for this purpose?
What the consistency model is used for the manual indexes - Do they use eventual consistency or strong consistency model between the index and the original data?

I agree Neo4J documentation on this issue is really insufficient.
To answer your questions:
1.If you upgraded your Neo4J from an older version that used automatic relationship index you would need to run APOC (only once) to index your existing relationships using something like
MATCH ()-[r]->() CALL apoc.index.addRelationship(r,['property_1','property_2']) RETURN count(*);
You would then need to set up a trigger to any new relationship you add to that index, running something like this once:
CALL apoc.trigger.add('RELATIONSHIP_INDEX',"UNWIND {createdRelationships} AS r MATCH ()-[r]->() CALL apoc.index.addRelationship(r,['property_1','property_2']) RETURN count(*)", {phase:'after'})
(you will need to activate apoc.trigger.enabled=true in neo4j.conf file before)
2.See above
3.You would need to remove them also from the index, it is not done automatically. Set up an APOC trigger with removeRelationshipByName() for that.
4.Should be possible.
5.Somebody from Neo4J should answer this.
Hope this helps and saves you some time!

Related

Enforcing the non-existence of relationships in Neo4j

In Neo4j, is there a way of enforcing that a node of a label X is not connected to a node of label Y?
For example, if someone tried to run a query such as:
MERGE (:X)-[:SOME_RELATIONSHIP]->(:Y)
would there be a way to guarantee that such a query would fail?
Thank you!
Neo4j's constraints don't currently support relationship existence or restriction, so you'd need to put in some extra work.
If you have APOC Procedures, you could register a trigger which could get evaluated to check if a relationship being created connects two nodes of those labels and use apoc.util.validate() to generate an error which will fail and rollback the transaction.
If you want to do this without APOC, it's a bit more work, as you'll need to create a TransactionEventHandler, and then a kernel extension to load your event handler. Here's a blog entry on this approach.

Cypher preventing a relationship from node b to a if the same relation from a to b exist?

I want to prevent a relationship between two nodes in Neo4j if the same relation from the different side is already present i.e.
create (a)-[r:Variation]->(b)
if and only if (b)-[r:Variation]->(a) is not present in the database ?
If your query only does relationship creation (nothing else after this), then just add WHERE NOT (b)-[:Variation]->(a) before your CREATE (I'm assuming there's a MATCH to a and b above this you didn't provide).
But if there's additional logic afterward and you want the query to keep executing whether or not the conditional is met, you may want to take a look at conditional procs in APOC Procedures, specifically apoc.do.when().

Create relationship with properties using a query in Cypher

I would like to know if this is possible. I have a query that produces a nice report showing a relationship between two entities through two other nodes. There can be more than one path. I now want to create a direct relationship between those two nodes and count the number of paths and sum based upon data in the nodes in between. the report query is below.
match (bo:BuyerAgency)<-[:IS_FOR_BO]-(sol:Solicitation)-[:SELECTED]->(prop:Proposal)<-[:OWNS_BID]-(so:VendorOrg)
where sol.currStatus='Awarded'
return bo.AgencyName, count(sol.Number) as awards, so.orgName, sum(prop.finalPrice) as awardVolume;
What I want to do is similar to below which will not work.
match (bo:BuyerAgency)<-[:IS_FOR_BO]-(sol:Solicitation)-[:SELECTED]->(prop:Proposal)<-[:OWNS_BID]-(so:VendorOrg)
where sol.currStatus='Awarded'
create (bo)-[:HAS_AWARDED{awardCount: count(sol.Number), awardVolume: sum(prop.finalPrice)}]->(so);
If I remove the properties for the relationship, it works but want to add the properties without to much programing.
I am using the most recent version of Neo4j 3.2.
thanks
The problem here is you are trying to use count() and sum() functions in an invalid context. The below query should work:
match (bo:BuyerAgency)<-[:IS_FOR_BO]-(sol:Solicitation)-[:SELECTED]->(prop:Proposal)<-[:OWNS_BID]-(so:VendorOrg)
where sol.currStatus='Awarded'
with bo, so, count(sol.Number) as count_sol, sum(prop.finalPrice) as sum_finalPrice
create (bo)-[:HAS_AWARDED{awardCount: count_sol, awardVolume: sum_finalPrice}]->(so);
This query uses WITH to pass bo, so and the result of the aggregation functions count(sol.Number) and sum(prop.finalPrice) to the next context. After, these values are used to create the new relation between bo and so.

Is node reference equality in embedded neo4j guaranteed?

I am using an embedded graph database as part of a java application. Suppose that I carry out some type of cypher query, and return an ExecutionResult which contains a collection of nodes.
These nodes may be assumed to form a connected graph.
Each of these nodes has some relationships, which I can access using node.getRelationships(Direction.OUTGOING). My question is, if the target of one of these relationships already occurs in the Execution result (i.e. the relationship is part of the query template), is it guaranteed that Relationship.getEndPoint == Node X.
I suppose that what I am really asking is, when a transaction in Neo4j returns a node, does it return just the one object, and different queries will just keep returning references to that one object, or does it keep producing new objects which happen to refer to the same data point? Since Node doesn't override the equalsTo method, I have been assuming the former, but I was hoping someone could tell me.
Nodes are not reference-equals. You'll only get NodeProxy objects which are created on the fly in different operations.
But the equals()-method does id-equality so you should use that.
n1.equals(n2)
or if you keep the node id around use
n1.getId() == n2.getId()
See when you create a node neo4j internally assigns it a node-id. All the relationships you create will have reference to the start node id and end node id.
For checking do this
First create a node and save its node id by calling method node.getId()
Now create a relationship to it from another node. And call your relationship.getEndNode().getId() .
You will see the node-ids are same.
It sounds like your asking - does Neo 'out of the box' give concurrency control of database entities, like n-hibernate or entity framework does for SQL.
The answer is no! You will have to manage it yourself. If you do delelop it though, could make you a few bob

Delete all relations and connected nodes in Neo4j for a user

We have selected neo4j as the DB for our web application. The user has a large number of relations and connected nodes. As of now there are about 20 relations for a user. One of the features is a newsfeed feature. If i want to delete a user completely, is the cypher query the best way to delete or is there any other alternative?
Since we are still planning to add new features, the relationships and nodes connected to the user also will increase. So if we use cypher query, the query has to be modified for every new relationship added. Please advise.
Thanks,
Pavan
Yes, you can use Cypher to remove a user. Of course, there are alternative methods, depending on the language or framework you're using with your web application. If you like to have advise on that, please specifiy how you're using Neo4j in detail.
Note that you have to remove all relationships (outgoing and incoming) first in order to be able to remove the node.
Example:
START n = node(3)
MATCH n-[r]-()
DELETE n, r
This example was taken from the official manual: http://docs.neo4j.org/chunked/milestone/query-delete.html
As of Neo4j 2.3 there is another way to do this:
MATCH (n { name:'Andres' })
DETACH DELETE n
I found this example in the documentation at: http://neo4j.com/docs/stable/query-delete.html
An alternative could be to write a gremlin script that traverses your graph starting with your user and is putting in two collection the relationships and the nodes that you intend to delete. If you want to delete everything, perhaps you can implement your depth first traversal in Gremlin and delete while traversing.

Resources