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

Reply via email to