I am learning neo4j , i want to know that is there any way that i can create a relationship or a node that will be delete automatically after a certain period of time.
As pointed out by #Scott in the comments, you can specify a TTL on nodes by using APOC as shown here. Append the following to your neo4j.conf:
apoc.ttl.enabled=true
Then you can either set the appropriate label and property yourself:
SET n:TTL
SET n.ttl = timestamp() + 3600
or utilize one of the following procedures:
// Expires in
CALL apoc.date.expire.in(node,time,'time-unit')
// Expires at
CALL apoc.date.expire(node,time,'time-unit')
There's nothing that I know of like this. Neo4j is just a database like *SQL or MongoDB (though let me know if they can do something like this).
The best suggestion that I would have is to put a delete_after property (or something similar) on the relationships and then have a job which queries on a regular basis to clean them up. Note that you can't query for relationships directly (that is, nodes always need to be involved in your query) so depending on how big your database is, you may need to think through what sort of index you need. I'm a bit vague here because I don't know what your domain model would look like.
If you are like me and stumble to this article, this has recently been updated.
Ref: https://neo4j.com/labs/apoc/4.3/overview/apoc.ttl/apoc.ttl.expireIn/
Match(person:person {id: 100})
CALL apoc.ttl.expireIn(person, 10,'s')
Return person;
Another option for Neo4j is using a Neo4j extension by GraphAware: neo4j-expire
One disadvantage of using such extensions is sometimes they stop supporting them for newer versions of Neo4j and also it takes some time for them to support the latest version. If these things are not a problem with you, you should have no problem with the extension.
Related
I want to connect two nodes without specifying the connection type but It doesn't seem to be possible. Why must relationships have a type? I tried the following:
(n)->(p)
(n)-->(p)
(n)-[]->(p)
(n)-[]-(p)
(n)-[c]->(p)
(n)-[:DEFAULT]->(p) // this works
My current approach is sort of described here, I have a DEFAULT connection type and when I know the real type, I change it by deleting the old one and adding the new one.
Unfortunately It's not possible currently, you can name it anything (like you are doing currently by naming it default) at the time of creating it and then change it later.
Changing the relationship type is not possible in Cypher (at least for now). Did you consider setting a property on the relationship to distinguish different kinds of relationships? It comes with a performance cost, so it depends on the MATCHes you plan to do, as well as on the use case.
I am using a "BatchInserter" to build a graph (in a single thread). I want to make sure nodes (and possibly relationships) are unique. My current solution is to check whether the node exists in the following manner:
String name = (String) nodeProperties.get(IndexKeys.CATEGORY_KEY);
if(index.get(IndexKeys.CATEGORY_KEY, name).size() > 0)
return index.get(IndexKeys.CATEGORY_KEY, name).getSingle();
Long nodeID = inserter.createNode( nodeProperties,categoryLabel );
index.add(nodeID, nodeProperties);
index.flush();
It seems to be working fine but as you can see it is IO expensive (flushing on every new addition - which i believe is a lucene "commit" command). This is slowing down my code considerably.
I am aware of put if absent and uniqueFactory. As documented:
By using put-if-absent functionality, entity uniqueness can be guaranteed using an index.
Here the index acts as the lock and will only lock the smallest part
needed to guaranteed uniqueness across threads and transactions. To
get the more high-level get-or-create functionality make use of
UniqueFactory
However, these are for transaction based interactions with the graph. What I would like to do is to ensure uniqueness of nodes and possibly relationships in a batch insertion semantics, that is faster than my current setup.
Any pointers would be much appreciated.
Thank you
You should investigate the MERGE keyword in cypher. I believe this will permit you to exploit your autoindexes without requiring you to use them yourself. More broadly, you might want to see if you can formulate your bulk load in a way that is conducive to piping large volumes of cypher queries through the neo4j-shell.
Finally, as general pointers and background, you should check out this information on bulk loading
When I encountered this problem, I just decided to go tyrant and force index values in my own. Can't you do the same? I mean, ensure uniqueness before you do the insertions?
Using Neo 2.0 through REST API /cypher I'm trying to build a rooted tree like structure.
I currently have an indexed start node, I want to attach a unique path of nodes which may already exist. How can I get cypher to create and set or just update if its already in the database but missing certain properties.
Cypher's MERGE command does this, see http://docs.neo4j.org/chunked/milestone/query-merge.html.
I have the same issue currently. I'm looking into CREATE UNIQUE might be what you are after.
http://neo4j.com/docs/stable/query-create-unique.html
edited: actually I think CREATE UNIQUE might be deprecated.
I am using the Neo4j .NET Client ExecuteGetCypherResults to run cypher. It expects everything to come back in a single column. I have simple class JobType which contains a list of JobSpecialties on it. In the database this is modeled as the Types having a relationship to the Specialties.
I need a cypher query that returns the results as such, in a single column. The related Specialties should be a child property of the Type node I would expect the query to look like this:
start s=node:node_auto_index(StartType='JobTypes')
match s-[:starts]->t, t-[:SubTypes]->ts
return {Id: t.Id, Name: t.Name, JobSpecialties: ts}
But this doesn't work. I can't figure out from the docs if this is even possible. If there is a better way to get the result back to the .Net client, I am open to suggestions.
start s=node:node_auto_index(StartType='JobTypes')
match s-[:SubTypes]->js
return s.Id, s.Name, js;
ExecuteGetCypherResults does support multiple columns, you just need to kick our deserializer into a different mode. This is an implementation detail generally hidden behind our higher level APIs, which is why this isn't obvious.
When you call new CypherQuery, pass CypherResultMode.Projection instead of CypherResultMode.Set.
I actually can't remember why we have this. Sometime, I'll need to dig through the lower levels and try and kill it. Pull requests welcomed. :)
As a preference though, we always prefer people to use the higher level APIs (but we recognise there are some limitations).
It sounds like the .Net client needs some updating for cypher. Cypher doesn't support building maps on the fly yet, although it is something that is in the feature request list already...
You can create an array with your results (but as of 1.9.M04, they need to be the same type to be merged into the array):
http://console.neo4j.org/r/xo7voi
I've actually submitted a pull request (through back channels, since it broke some unit tests) to fix that (so you can have multiple types in an array built on the fly), but I think there are some concerns whether merging of different types is a good idea.
https://github.com/wfreeman/neo4j/commit/ca457ace0df4732376833b8694e4affac4143244
Update: This will be fixed in 1.9.M05/1.9.GA. Now you can build an array with any type mixed:
http://console.neo4j.org/r/vm4f83
I'm using Spring data neo4j 2.1.0.BUILD-SNAPSHOT and Neo4j 1.6.1 server.
I have a Friendship relationship between two User nodes, and I want to ensure that only one relationship will be created for every user1, user2 pair (the order doesn't count).
Common suggestion is to check at application level if a relationship already exists before creating another one, but I think that doesn't avoid concurrency problems: the constraint should be managed at the database level.
The best solution I can think of is to use the #Indexed annotation with unique property introduced in Neo4j 1.6 and create a unique constraint based on the user1 and user2 ids, something like
#Indexed(unique = true)
private String uniqueConstraint;
public String getUniqueConstraint(){
if(user1.id > user2.id){
return user1.id + "|" + user2.id;
}
return user2.id + "|" + user1.id;
}
BTW I know that the latest release of Spring data neo4j supports this check on nodes with Neo4jTemplate.getOrCreateNode(), but I'm not sure it works with Relationships. The rest API should be there though. Unique relationship
So I have two questions:
1 Is there any better alternative?
2 Should I be bothered by this concurrency problem, or it's very unlikely that something bad happens even in a high traffic site and the check at application level should be sufficient? I ask because it seems to me a very common problem, but there's little around about this with Neo4j. Maybe the embedded version suffers less from this.
Thanks
The usual approach in SDN of having relationships between two nodes already ensures that there is only one relationship of one type between them (by checking upfront).
It doesn't yet leverage the uniqueness support in Neo4j for that.
And yes, with the REST-Server this approach might run into concurrency/racing conditions.
The embedded version supports locking (e.g. on one of the 2 nodes - or both) and then creating the relationship with that lock in place. So that there is no second thread doing the same thing at the same time.
It might be ok, if you do it optimistically. I.e. check after creation and delete afterwards. You can also leverage the REST-API directly to support that behaviour. We probably add support for that by SDN 2.1 could you raise an issue (linking to this post) at http://spring.neo4j.org/issues ?