简体   繁体   中英

How to Increment consistently in Neo4j, Cypher is too slow?

Im currently using Neo4j 2.0+ and cypher to create and save sessions.

My project at times requires multiple writes per second to a node labeled 'ChildSession', and I notice that when I 'increment' the ChildSession_ID in cypher, I often have ChildSession_ID's skipping numbers or being the same number.

Not sure if neo4j/cypher is too slow for my requirements, but I doubt it since the internal Neo4j Node ID's are incremented normally.

The cypher command i'm using, to increment ChildSession is:

 match (p:ChildSession) with count(p) as Total 
 Create (b:ChildSession{ChildSession_ID:Total + 1 })

One would expect the ChildSession_ID to increment, but I get the following results, when I check the nodes in neo4j browser:

match (u:ChildSession) return u,ID(u)

Results:
ChildSession_ID 1
44997
ChildSession_ID 1
44998
ChildSession_ID 1
44999
ChildSession_ID 4
45000
ChildSession_ID 5
45001
ChildSession_ID 6
45002
ChildSession_ID 6
45003
ChildSession_ID 8
45004
ChildSession_ID 8
45005

I've been unable to get neo4j to increment accurately. I tried using redis and its hincrby command which increments and then put this variable into my cypher query's ChildSession_ID attribute. This method works, but I would rather do it with cypher instead.

The argument could be made to use redis only instead for fast writes, but I use a hiearchy of session levels and need the querying neo4j offers.

Thanks.

Have you added any manual locking around access to the ChildSession label? I would expect otherwise that the MATCH statement could happen on multiple threads at the same time (no read locking). The result of this would be the same value for Total being passed to your CREATE statement.

Two things spring to mind, using the COUNT is maybe not the fastest and would not guarantee unique values if you were ever to delete a ChildSession (maybe you do not care?). Maintaining the count as a property is probably faster (query time) and incurs minimal overhead.

I believe that the correct way to achieve this is to use a MERGE statement on a separate label which should lock on the Incremental Node through the whole transaction (as described in this Blog Post ):

MERGE (nid:Incremental{type:ChildSession})
ON CREATE SET nid.count = 1
ON MATCH SET nid.count = nid.count + 1
RETURN nid.count

Caveat: Whilst I believe this is the correct way to do it, I'll be damned if it is working nicely in a rapid async environment, suggesting that the semantics of the locking are not what I expect.

You could of course generate a UUID if the incremental nature of your ChildSession_ID is not important?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM