optimistic concurrency with neo4j using the REST API - neo4j

Is there any way to implement optimistic concurrency during updating and creating neo4j nodes using the REST API? I'd like to create a user node with a unique name only if that name doesn't exist. Don't want two users to accidentally overwrite each other if they pick the same username at the same time.
Additionally, I'd could also have something like an incrementing version number to check for concurrency on the node. In SQL I would normally have an update with a where clause that checks for id and version number. Is there something similar I can do with cypher that would be easy to implment and wouldn't require me to type all the property names out into a long query?

You could try a unique index: http://docs.neo4j.org/chunked/stable/rest-api-unique-indexes.html
Cypher "CREATE UNIQUE" syntax may also be a help: http://docs.neo4j.org/chunked/stable/query-create-unique.html

Related

What is the difference between randomUUID and GraphAware UUID in Neo4j?

I am currently using GraphAware UUID Library to generate UUID in neo4j, later I found out that it has a randomUUID() function to generate UUID, which one should be used?, will randomUUID() create unique id on server?
They both call java.util.UUID#randomUUID(), that's where the similarity between them ends.
The built-in Cypher's randomUUID() is a function, which you have to call manually in each cypher query where you want to assign a UUID.
The neo4j-uuid module is a set of extensions to Neo4j, which allow you to transparently assign UUID (or other types of ids - depending on configured id generator) to nodes and relationships, ensures the ids can't be changed or deleted. It also maintains an explicit index for the nodes / relationships. See the readme for the full feature set.
If your use case is simply to assign a uuid to (some) nodes or relationships then use the built in function. If you can take advantage of the other features of the neo4j-uuid module - use that.
For manual use cases, creating the UUID yourself in a Cypher query, they're functionally identical (GraphAware implemented this first I think, we got to it later). Yes the ids will be created on the server and will be unique, both
I believe GraphAware's UUID module covers more than just this, doing automatic assigning of UUIDs to newly created nodes and relationships and extra validation on top of that.

How to determine the Max property on a Relationship in Neo4j 2.2.3

How do you quickly get the maximum (or minimum) value for a property of all instances of a relationship? You can assume the machine I'm running this on is well within the recommended spec's for the cpu and memory size of graph and the heap size is set accordingly.
Facts:
Using Neo4j v2.2.3
Only have access to modify graph via Cypher query language which I'm hitting via PHP or in the web interfacxe--would love to avoid any solution that requires java coding.
I've got a relationship, call it likes that has a single property id that is an integer.
There's about 100 million of these relationships and growing
Every day I grab new likes from a MySQL table to add to the graph within in Neo4j
The relationship property id is actually the primary key (auto incrementing integer) from the raw MySQL table.
I only want to add new likes so before querying MySQL for the new entries I want to get the max id from the likes, so I can use it in my SQL query as SELECT * FROM likes_table WHERE id > max_neo4j_like_property_id
How can I accomplish getting the max id property from neo4j in a optimal way? Please indicate the create statement needed for any index as well as the query you'd used to get the final result.
I've tried creating an index as follows:
CREATE INDEX ON :likes(id);
After the index is online I've tried:
MATCH ()-[r:likes]-() RETURN r.i ORDER BY r.id DESC LIMIT 1
as well as:
MATCH ()-[r:likes]->() RETURN MAX(r.id)
They work but take freaking forever as the explain plan for both indicate no indexes being used.
UPDATE: Holy $?##$?!!!! It looks like the new schema indexes aren't functional for relationships even though you can create them and show them with :schema. It also looks as if there's no way with cypher directly to create Legacy Indexes which look like they might solve this issue.
If you need to query relationship properties, it is generally a sign of a model issue.
The need of this query reveals you that you would better extract these properties into a node, that you'll then be able to query faster.
I don't say it is 100% the case, but certainly 99% of the people seen so far with the same problem has been demonstrating this model concern.
What is your model right now ?
Also you don't use labels at all in your query, likes have a context bound to the nodes.

How to use "MATCH.. CREATE UNIQUE.." with neography

I'm trying to write an importer script that will take a MySQL resultset and add nodes and relationships in my Neo4J DB. To simplify things, my resultset has the following fields:
application_id
amount
application_date
account_id
I want to create a node with Application label with the application_id, amount, application_date fields and another node with Account label with account_id field and a relationship between them.
My SQL query is from the applications table so I'm not afraid of dups there, but an account_id can appear more than once and I obviously don't want to create multiple nodes for that.
I'm using neography (but willing to switch if there is something simpler). What would be the best (easiest) way to achieve that?
My script will drop the database before it starts so no leftovers to take care of.
Should I create an index before and use create_unique_node?
I think I can do what I want in cypher using "MATCH .. CRAETE UNIQUE..", what's the equivalent of that in neography? I don't understand how index_name gets into the equation...
Should I or should I not define the constraint on Account?
Many thanks,
It's my first time with graph DBs so apologies if I miss a concept here..
From what you describe, it looks like you should use the constraints that come with Neo4j 2.0 : http://docs.neo4j.org/chunked/milestone/query-constraints.html#constraints-create-uniqueness-constraint
CREATE CONSTRAINT ON (account:ACCOUNT) ASSERT account.account_id IS UNIQUE
Then you can use the MATCH .. CREATE UNIQUE clauses for all your inserts. You can use neography to submit the cypher queries, see the examples here: https://github.com/maxdemarzi/neography/wiki/Scripts-and-queries

Understanding Neo4j, creating unique nodes

I'm trying to wrap my head around how Neo4j works and how I can apply it to my problem. I thought it should be really easy and a matter of minutes, but I'm stuck.
I have data in MongoDB, say User and Item. What I want is connecting User and Item in a graph with a LIKE relationship (maybe with a score). Later I want to do things like recommending items based on connections, basic stuff.
But how do I get the data into Neo4j? Every document in MongoDB has an unique _id, so I though I could just throw both _ids into Neo4j and have them connected. What I found so far is that it's not even possible to have unique nodes based on the _id field (Neo4j has numeric incremented ids), which is only possible with some "hack" (https://github.com/jexp/app-net-graph/blob/master/lib/appnet.rb#L11) or using MERGE (I'm stuck on < 2.0). Even their examples on the website add the same node again if executed multiple times. I think I have a fundamental misunderstanding of how to use Neo4j. Maybe I'm too spoiled by redis, where I can put strings in and and it just works. Redis' sets aren't feasible though for complex graphs, only for simple connections.
Maybe someone can help me with a simple cypher example of how to add two nodes foo and bar and have them connected with a LIKE connection. And the operation should be idempotent, no matter if none or all of the nodes/relationships already existed before execution.
I'm accessing Neo4j via REST, in particular using this node module https://github.com/thingdom/node-neo4j
You could define your external ID as extra property on your nodes. Then depending on if your are using SpringData or not, you can insert the data.
If you are using SpringData, you can configure your external ID as unique index and then normally save you nodes(consider though, that inserting a duplicated ID will overwrite the existing one).
If you are using the plain java API, you can create unique nodes as described here:
http://docs.neo4j.org/chunked/stable/tutorials-java-embedded-unique-nodes.html#tutorials-java-embedded-unique-get-or-create
EDIT:
As for a sample query, does this help you?
http://console.neo4j.org/?id=b0z486
With the java api you would do it like this
firstNode = graphDb.createNode();
firstNode.setProperty( "externalID", "1" );
firstNode.setProperty( "name", "foo" );
secondNode = graphDb.createNode();
secondNode.setProperty( "externalID", "2" );
secondNode.setProperty( "name", "bar" );
relationship = firstNode.createRelationshipTo( secondNode, RelTypes.Likes );
I suggest you read some tutorials here: http://docs.neo4j.org/chunked/stable/tutorials-java-embedded-hello-world.html
Given you are using Neo4J1.9, have you tried creating a unique index on your _ID column?
Try this article from the docs
If you were using Neo4j2, then this article is helpful

Enforce relationship uniqueness with Neo4j

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 ?

Resources