Linan, It's high prio in the backlog for 1.6, so this WILL be taken care of. I believe there is also an issue on this on Github? If not, please raise one to track progress for the community. Thanks!
/peter Sent from my phone. On Sep 28, 2011 10:02 PM, "Linan Wang" <tali.w...@gmail.com> wrote: > Peter, > I feel uniqueness has been a recurring theme in neo4j applications, > especially when it's used heavily on algorithms traversing existing > data. it would be great if it's supported in kernel level: > > interface NodeUniquenessConstraint > { > public Node getNode(); > public void setupNode(Node newNode); > } > > public Node getOrCreateNode(NodeUniquenessConstraint constraint) > { > // Preparation, acquires lock, etc. > Node n = constraint.getNode(); > if(n == null) > { > n = createNode(); > constraint.setupNode(n); > } > ... > return n; > } > > or, there is something similar already implemented? > > On Tue, Sep 27, 2011 at 9:38 PM, Peter Neubauer > <peter.neuba...@neotechnology.com> wrote: >> Guys, >> Maps are now supported as parameters, look at the Gremlin plugin för >> reference in the docs. Will add that for parameters to the cypher plugin >> too. >> >> Thanks for chipping in! >> >> /peter >> >> Sent from my phone. >> On Sep 27, 2011 8:12 PM, "Tony Wooster" <twoos...@gmail.com> wrote: >>> Hi Linan, >>> >>> That's essentially what I implemented, but the logic just became that >>> much more tortured when going over REST. Like I said, less of a Java >>> programmer. The implementation I came up with on the REST side (hacky >>> though it may be) was this: >>> >>> @Description( "An extension to help maintain unique relationships" ) >>> public class IndexTester extends ServerPlugin >>> { >>> @Name( "error_if_in_node_index" ) >>> @Description( "Will return a 4xx error if a key/value pair is found in >> "+ >>> "a given index. Also errors if the index doesn't >> exist.") >>> @PluginTarget( GraphDatabaseService.class ) >>> public Boolean errorIfInNodeIndex( >>> @Source GraphDatabaseService graphDb, >>> @Description( "Name of the index to earch." ) >>> @Parameter( name = "indexName" ) String indexName, >>> @Description( "Name of key to search." ) >>> @Parameter( name = "key" ) String key, >>> @Description( "Value to search for." ) >>> @Parameter( name = "value" ) String value ) >>> throws BadInputException >>> { >>> >>> if ( !graphDb.index().existsForNodes( indexName ) ) >>> throw new BadInputException("Index doesn't exist", new >>> NotFoundException()); >>> >>> Index<Node> index = graphDb.index().forNodes( indexName ); >>> >>> if (index.get(key, value).size() > 0) >>> throw new BadInputException("Key/value pair found in index"); >>> return null; >>> } >>> } >>> >>> I'm still not entirely certain that this is the appropriate way to go; >>> probably a better solution would be a more general "add node with >>> unique, indexed fields" command that's slightly more functional than >>> this batch-operation-quirks based hack. As an aside -- does anyone >>> know when/if lists of maps for parameters will be implemented for REST >>> plugins? >>> >>> Thanks for the response! >>> >>> -T >>> >>> On Thu, Sep 22, 2011 at 4:57 PM, Linan Wang <tali.w...@gmail.com> wrote: >>>> >>>> Hi, >>>> i had the issue few days ago and thanks to McKinley I got a workable >>>> solution. i think the best way to do is through unmanaged extension. >>>> the overhead of multiple REST calls could make the matter more >>>> complex. >>>> >>>> here is part of my ObjectFactory class. in my situation it's an >>>> external id needs to be uniq. feel free to correct my codes :) the >>>> performance is not ideal though. on my imac I got around 50 insertions >>>> per sec. the bottle neck is not memory. >>>> >>>> public T get(long externalId) >>>> { >>>> // try asynchronized read first; >>>> Index<Node> idx = getDefaultNodeIndex(); >>>> >>>> IndexHits<Node> h = idx.get(IDX_KEY_EXTERNAL_ID, >> externalId); >>>> Node n = h.getSingle(); >>>> h.close(); >>>> >>>> if(n != null) >>>> return wrap(n); >>>> >>>> // if not found, try synchronized version; >>>> return null; >>>> } >>>> >>>> public T getOrCreate(long externalId) >>>> { >>>> >>>> T ret = get( externalId ); >>>> if(ret != null) >>>> return ret; >>>> >>>> // if not found, try synchronized version; >>>> return synchronizedGetOrCreate(externalId); >>>> } >>>> >>>> private synchronized T synchronizedGetOrCreate(long externalId) >>>> { >>>> // Just in case! >>>> T ret = get( externalId ); >>>> if(ret != null) >>>> return ret; >>>> >>>> Index<Node> idx = getDefaultNodeIndex(); >>>> Node n = null; >>>> >>>> Transaction tx = db.beginTx(); >>>> >>>> try{ >>>> n = db.createNode(); >>>> >>>> // set property >>>> n.setProperty(AbstractObject.EXTERNAL_ID_KEY, >> externalId); >>>> >>>> // add to default index; >>>> idx.add(n, IDX_KEY_EXTERNAL_ID, externalId); >>>> >>>> tx.success(); >>>> }catch(Exception e){ >>>> tx.failure(); >>>> }finally{ >>>> tx.finish(); >>>> } >>>> >>>> return wrap(n); >>>> } >>>> >>>> On Thu, Sep 22, 2011 at 9:33 PM, twooster <twoos...@gmail.com> wrote: >>>> > Hi, >>>> > >>>> > I've seen this come up a number of times in various forms on the >> mailing >>>> > list, but -- while there are some scattered answers here and there -- >> there >>>> > doesn't seem to be much of a definitive solution. The problem I'm >> looking to >>>> > solve is basic uniqueness (e.g. for creating an account -- unique >> username >>>> > or email address); to make matters more complicated, I'd like to do >> this >>>> > over the REST interface. >>>> > >>>> > In the a non-REST use of Neo4j, it sounds like I could achieve this by >> doing >>>> > the following: >>>> > >>>> > 1. Begin a transaction >>>> > 2. Acquire a write lock on a UserRef supernode, say by attempting to >> delete >>>> > the property __WRITE_LOCK__ (which will fail if the property doesn't >> exist, >>>> > say) >>>> > 3. Check if username is in users index >>>> > 4. If it is, cancel transaction and fail >>>> > 5. Otherwise, add a User node, relate it back to the UserRef node, and >> add >>>> > it to the index >>>> > 6. Release lock on UserRef supernode by re-adding __WRITE_LOCK__ >> property >>>> > 7. Commit transaction >>>> > >>>> > First -- does this sound roughly sound? Assuming that any operation >> that >>>> > ever touches the index agrees to first "acquire" a write lock in this >>>> > manner, are there any tricky concurrency issues (maybe out-of-sync >> indexes, >>>> > or the index.get(key,v).size() function being "almost correct") that >> I'm >>>> > missing? >>>> > >>>> > To complicate matters, I'd _like_ to do this with REST, not the least >> reason >>>> > because my main project code is in Python, and neo4j.py seems to be >>>> > relatively unmaintained compared to the REST client. It's my >> understanding >>>> > that transactions are handled using the batch interface. The only way >> to >>>> > make the transaction fail is if any given operation returns a non-2xx >> status >>>> > code. Thus, the 'if value is found in an index' thing is somewhat >> difficult >>>> > to implement given the basic REST primitives. >>>> > >>>> > After cozying up with the code for a number of hours last night, my >> first >>>> > real foray into Java programming, it appears that I can achieve the >>>> > behaviour I want by introducing a REST plugin (an unmanaged extension >> would >>>> > be cleaner, but the big warning and limited documentation dissuaded me) >> that >>>> > throws an exception if a value _is_ found in a given index (which will >> cause >>>> > the plugin invoker to return a 4xx response). Now my workflow over REST >>>> > looks like this: >>>> > >>>> > 1. Begin transaction (e.g., start a batch request to the server), >> issuing >>>> > the following commands: >>>> > 2. Attempt to delete __WRITE_LOCK__ from UserRef node (will 4xx if >> property >>>> > is non-existent) >>>> > 3. POST to extension, to check if username is in users index (4xx if it >>>> > exists) >>>> > 3a. Transaction will fail at this point if user is in index >>>> > 4. Add a User node >>>> > 5. Relate it back to the UserRef node >>>> > 5. Add it to the index >>>> > 6. Release lock on UserRef supernode by re-adding __WRITE_LOCK__ >> property >>>> > 7. Finish HTTP request, done >>>> > >>>> > This seems to work, but, again, are there any blind-spots that I'm >> unaware >>>> > of? How about if this goes to a HA cluster? >>>> > >>>> > Finally, somewhat related, are some concerns with the batch API >>>> > back-reference capability. This appears to manifest itself as a blind >>>> > string-replace of '{[id]}' in provided fields. This _seems_ like it >> could >>>> > have some security/annoying bug concerns relating to user-provided data >>>> > (local portion of email address includes the substring '{1}', for >> example, >>>> > which is valid per the email spec). I currently don't see any way >> around >>>> > this except to restrict user input. Any thoughts? >>>> > >>>> > Anyway, thanks for any comments and responses! >>>> > >>>> > -Tony Wooster >>>> > >>>> > -- >>>> > View this message in context: >> http://neo4j-community-discussions.438527.n3.nabble.com/REST-Transactions-and-Uniqueness-tp3360054p3360054.html >>>> > Sent from the Neo4j Community Discussions mailing list archive at >> Nabble.com. >>>> > _______________________________________________ >>>> > Neo4j mailing list >>>> > User@lists.neo4j.org >>>> > https://lists.neo4j.org/mailman/listinfo/user >>>> > >>>> >>>> >>>> >>>> -- >>>> Best regards >>>> >>>> Linan Wang >>>> _______________________________________________ >>>> Neo4j mailing list >>>> User@lists.neo4j.org >>>> https://lists.neo4j.org/mailman/listinfo/user >>> _______________________________________________ >>> Neo4j mailing list >>> User@lists.neo4j.org >>> https://lists.neo4j.org/mailman/listinfo/user >> _______________________________________________ >> Neo4j mailing list >> User@lists.neo4j.org >> https://lists.neo4j.org/mailman/listinfo/user >> > > > > -- > Best regards > > Linan Wang > _______________________________________________ > Neo4j mailing list > User@lists.neo4j.org > https://lists.neo4j.org/mailman/listinfo/user _______________________________________________ Neo4j mailing list User@lists.neo4j.org https://lists.neo4j.org/mailman/listinfo/user