<p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/vlg/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/vlg">@vlg</a>: 'OK so there is an issue with key-value automatic indices (code bellow) upon node removal. The scenario tested here is the following:</p>
<p dir="auto">Assume that we index a property named 'ID', and that we want to use it to manage unicity of nodes. We create a database, and init indexing of this property, then we do the following:<br>
addNode('N1)<br>
deleteNode('N1)<br>
graph.shutdown()<br>
graph.openAgain()<br>
addNode('N1')<br>
addNode('N2')<br>
getNodeFromIndex('ID', 'N1)</p>
<p dir="auto">The issue is that nothing is retrieved by the last instruction while N1 should be retrieved. Additional observations:</p>
<p dir="auto">(1) If we add N2 BEFORE N1, results are OK<br>
(1) If we do not remove N1, results are OK<br>
(2) If we don't close and reopen the database, results are OK<br>
(3) If we drop the reference node at the database creation, results are OK</p>
<p dir="auto">CODE:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="import java.util.logging.Level;
import java.util.logging.Logger;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.NotFoundException;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.index.IndexHits;
import org.neo4j.kernel.EmbeddedGraphDatabase;

public class Neo4jKeyIndexIssues
{    
    public static final String DBPATH   = &quot;NeoTest&quot; ;
    public static final String INDEXED  = &quot;ID&quot; ;
    public static final String N1       = &quot;Node1&quot; ;
    public static final String N2       = &quot;Node2&quot; ;


    public static void main(String[] args) 
        throws Exception {

        Node node1, node2 ;

        GraphDatabaseService g =  new EmbeddedGraphDatabase(DBPATH);
        g.index().getNodeAutoIndexer().setEnabled(true);
        g.index().getNodeAutoIndexer().startAutoIndexingProperty(INDEXED);

        // dropNeoReferenceNode(g);

        System.out.println(&quot;(1)&quot;);
        node1 = addNode(g, N1);

        IndexHits&lt;Node&gt; hits = g.index().getNodeAutoIndexer().getAutoIndex().get(INDEXED, N1);
        System.out.println(&quot;1) Query Hits for '&quot;+N1+&quot;': &quot; + hits.size()+&quot; &quot;+hits.hasNext());
        Node hit = hits.getSingle();
        System.out.println(&quot;1) Hit for '&quot;+N1+&quot;': &quot; + hit.getProperty(INDEXED));

        // Remove the nodes
        Transaction tx = g.beginTx();
        System.out.println(&quot;Removing node 1 &quot;+N1);
        node1.delete();
        tx.success(); tx.finish();

        // Reopen database
        System.out.println(&quot;-Shutting down and reopening the database-&quot;);
        g.shutdown();
        g = new EmbeddedGraphDatabase(DBPATH);
        g.index().getNodeAutoIndexer().setEnabled(true);
        g.index().getNodeAutoIndexer().startAutoIndexingProperty(INDEXED);

        // OK, add new nodes again
        System.out.println(&quot;\n(2)&quot;);
        node1 = addNode(g, N1);
        node2 = addNode(g, N2);

        hits = g.index().getNodeAutoIndexer().getAutoIndex().get(INDEXED, N1);
        System.out.println(&quot;2) Query Hits for 'N1': &quot;+hits.size()+&quot; &quot;+hits.hasNext());

        // Something should be found
        node1 = hits.getSingle();
        if(node1 == null) {
            System.out.println(&quot;2) ERROR: nothing found ID='&quot;+N1+&quot;'&quot;);
        }
        else {
            System.out.println(&quot;2) Hit for 'N1': &quot; + node1+&quot; ID=&quot;+node1.getProperty(&quot;ID&quot;));
        }

        // Something should be found too
        hits = g.index().getNodeAutoIndexer().getAutoIndex().get(INDEXED, N2);
        System.out.println(&quot;2) Query Hits for 'N2': &quot;+hits.size()+&quot; &quot;+hits.hasNext());

        // Nothing was found
        node2 = hits.getSingle();
        if(node2 == null) {
            System.out.println(&quot;2) ERROR: nothing found ID='&quot;+N2+&quot;'&quot;);
        }
        else {
            System.out.println(&quot;2) Hit for 'N2': &quot; + node2+&quot; ID=&quot;+node2.getProperty(&quot;ID&quot;));
        }

        g.shutdown();
    }

    /**
    * Add a node to a database, only if a node with the same identifier does not
    * exist yet.
    */
    private static Node addNode(GraphDatabaseService g, String id) 
        throws Exception {
        System.out.println(&quot;Adding node &quot;+id);

        Transaction tx = g.beginTx();

        Node node = null ;
        try {
            IndexHits&lt;Node&gt; hits = 
                    g.index().getNodeAutoIndexer().getAutoIndex().get(&quot;ID&quot;, id);

            System.out.println(&quot;   Existing nodes in index: &quot;+hits.size()+&quot; &quot;+hits.hasNext());
            if(hits.size() &gt; 0 &amp;&amp; hits.hasNext()) {
                System.out.print(&quot;   Duplicate: &quot;+id);

                node = hits.getSingle();
                System.out.println(&quot; --&gt; &quot;+node);
                return node;
            }

            node = g.createNode();
            node.setProperty(&quot;ID&quot;, id);

            tx.success();
        }
        catch(Exception e) {
            Logger.getLogger(&quot;App&quot;).log(Level.FINE,
                                        &quot;Could not add node node &quot;+id, e);
            throw e ;
        }
        finally {
            tx.finish();
        }

        System.out.println(&quot;   Node added: &quot;+node);

        return node;
    }

    /**
    * Drop the refernce node from a database
    */
    private static void dropNeoReferenceNode(GraphDatabaseService neoGraph) {
        Transaction t = neoGraph.beginTx();
        try {
            Node node = neoGraph.getReferenceNode();
            if (node != null) {
                node.delete();
            }
            t.success();
        }
        catch (NotFoundException e) {
            Logger.getLogger(&quot;App&quot;).log(Level.FINE,
                                        &quot;Could not drop reference node!&quot;, e);
            t.failure();
        }
        finally {
            t.finish();
        }
    }
}"><pre class="notranslate"><code class="notranslate">import java.util.logging.Level;
import java.util.logging.Logger;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.NotFoundException;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.index.IndexHits;
import org.neo4j.kernel.EmbeddedGraphDatabase;

public class Neo4jKeyIndexIssues
{    
    public static final String DBPATH   = "NeoTest" ;
    public static final String INDEXED  = "ID" ;
    public static final String N1       = "Node1" ;
    public static final String N2       = "Node2" ;


    public static void main(String[] args) 
        throws Exception {

        Node node1, node2 ;

        GraphDatabaseService g =  new EmbeddedGraphDatabase(DBPATH);
        g.index().getNodeAutoIndexer().setEnabled(true);
        g.index().getNodeAutoIndexer().startAutoIndexingProperty(INDEXED);

        // dropNeoReferenceNode(g);

        System.out.println("(1)");
        node1 = addNode(g, N1);

        IndexHits&lt;Node&gt; hits = g.index().getNodeAutoIndexer().getAutoIndex().get(INDEXED, N1);
        System.out.println("1) Query Hits for '"+N1+"': " + hits.size()+" "+hits.hasNext());
        Node hit = hits.getSingle();
        System.out.println("1) Hit for '"+N1+"': " + hit.getProperty(INDEXED));

        // Remove the nodes
        Transaction tx = g.beginTx();
        System.out.println("Removing node 1 "+N1);
        node1.delete();
        tx.success(); tx.finish();

        // Reopen database
        System.out.println("-Shutting down and reopening the database-");
        g.shutdown();
        g = new EmbeddedGraphDatabase(DBPATH);
        g.index().getNodeAutoIndexer().setEnabled(true);
        g.index().getNodeAutoIndexer().startAutoIndexingProperty(INDEXED);

        // OK, add new nodes again
        System.out.println("\n(2)");
        node1 = addNode(g, N1);
        node2 = addNode(g, N2);

        hits = g.index().getNodeAutoIndexer().getAutoIndex().get(INDEXED, N1);
        System.out.println("2) Query Hits for 'N1': "+hits.size()+" "+hits.hasNext());

        // Something should be found
        node1 = hits.getSingle();
        if(node1 == null) {
            System.out.println("2) ERROR: nothing found ID='"+N1+"'");
        }
        else {
            System.out.println("2) Hit for 'N1': " + node1+" ID="+node1.getProperty("ID"));
        }

        // Something should be found too
        hits = g.index().getNodeAutoIndexer().getAutoIndex().get(INDEXED, N2);
        System.out.println("2) Query Hits for 'N2': "+hits.size()+" "+hits.hasNext());

        // Nothing was found
        node2 = hits.getSingle();
        if(node2 == null) {
            System.out.println("2) ERROR: nothing found ID='"+N2+"'");
        }
        else {
            System.out.println("2) Hit for 'N2': " + node2+" ID="+node2.getProperty("ID"));
        }

        g.shutdown();
    }

    /**
    * Add a node to a database, only if a node with the same identifier does not
    * exist yet.
    */
    private static Node addNode(GraphDatabaseService g, String id) 
        throws Exception {
        System.out.println("Adding node "+id);

        Transaction tx = g.beginTx();

        Node node = null ;
        try {
            IndexHits&lt;Node&gt; hits = 
                    g.index().getNodeAutoIndexer().getAutoIndex().get("ID", id);

            System.out.println("   Existing nodes in index: "+hits.size()+" "+hits.hasNext());
            if(hits.size() &gt; 0 &amp;&amp; hits.hasNext()) {
                System.out.print("   Duplicate: "+id);

                node = hits.getSingle();
                System.out.println(" --&gt; "+node);
                return node;
            }

            node = g.createNode();
            node.setProperty("ID", id);

            tx.success();
        }
        catch(Exception e) {
            Logger.getLogger("App").log(Level.FINE,
                                        "Could not add node node "+id, e);
            throw e ;
        }
        finally {
            tx.finish();
        }

        System.out.println("   Node added: "+node);

        return node;
    }

    /**
    * Drop the refernce node from a database
    */
    private static void dropNeoReferenceNode(GraphDatabaseService neoGraph) {
        Transaction t = neoGraph.beginTx();
        try {
            Node node = neoGraph.getReferenceNode();
            if (node != null) {
                node.delete();
            }
            t.success();
        }
        catch (NotFoundException e) {
            Logger.getLogger("App").log(Level.FINE,
                                        "Could not drop reference node!", e);
            t.failure();
        }
        finally {
            t.finish();
        }
    }
}
</code></pre></div>
<p dir="auto">'</p>
<p dir="auto">Currently there doesn't seem to be a way to configure the isolation level for a transaction (especially SERIALIZABLE) when using the REST API.</p>
<p dir="auto">I'm trying to create friendly id's for child objects using the following:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="CREATE (o:Foo {name: 'parent', nextChildId: 1})

MATCH (o:Foo)
WHERE o.name = 'parent'
CREATE (o)-[:HAS]-&gt;(c:Child {name: 'child1', friendlyId: o.nextChildId})
SET o.nextChildId = o.nextChildId + 1

// if this call comes in before the previous SET, we have a problem
MATCH (o:Foo)
WHERE o.name = 'parent'
CREATE (o)-[:HAS]-&gt;(c:Child {name: 'child2', friendlyId: o.nextChildId})
SET o.nextChildId = o.nextChildId + 1"><pre class="notranslate"><code class="notranslate">CREATE (o:Foo {name: 'parent', nextChildId: 1})

MATCH (o:Foo)
WHERE o.name = 'parent'
CREATE (o)-[:HAS]-&gt;(c:Child {name: 'child1', friendlyId: o.nextChildId})
SET o.nextChildId = o.nextChildId + 1

// if this call comes in before the previous SET, we have a problem
MATCH (o:Foo)
WHERE o.name = 'parent'
CREATE (o)-[:HAS]-&gt;(c:Child {name: 'child2', friendlyId: o.nextChildId})
SET o.nextChildId = o.nextChildId + 1
</code></pre></div>
<p dir="auto">But without being able to take a lock on the <code class="notranslate">parent</code> node there isn't a way to prevent two <code class="notranslate">child</code> nodes from getting assigned the same friendly id.</p>