Getting NotInTransactionException while querying neo4j index - neo4j

I am currently using neo4j 1.8.1 . I am getting NotInTransactionException , when I am querying the neo4j index to get some nodes.
Following is a simple query , which i am executing on neo4j
if (graphDb.index().existsForNodes("NODEINDEX")) {
IndexHits<Node> hits = graphDb.index().forNodes(NODEINDEX).query(query);
}
The following is stacktrace for the exception.
"message" : "Error fetching transaction for current thread",
"exception" : "NotInTransactionException",
"stacktrace" : [ "org.neo4j.kernel.impl.index.IndexConnectionBroker.getCurrentTransaction(IndexConnectionBroker.java:134)", "org.neo4j.kernel.impl.index.IndexConnectionBroker.acquireReadOnlyResourceConnection(IndexConnectionBroker.java:84)", "org.neo4j.index.impl.lucene.LuceneIndex.getReadOnlyConnection(LuceneIndex.java:105)", "org.neo4j.index.impl.lucene.LuceneIndex.query(LuceneIndex.java:245)", "org.neo4j.index.impl.lucene.LuceneIndex.query(LuceneIndex.java:227)", "org.neo4j.index.impl.lucene.LuceneIndex.query(LuceneIndex.java:238)", "com.uprr.netcontrol.starmap.neo4j.plugins.aggregate_node_status.NodeStatusHelper.getGraphNodes(NodeStatusHelper.java:39)",
I found the following in Neo4j api.
private Transaction getCurrentTransaction() throws NotInTransactionException
{
try
{
return transactionManager.getTransaction();
}
catch ( SystemException se )
{
throw new NotInTransactionException(
"Error fetching transaction for current thread", se );
}
}
Do we need to explicitly start a transaction for querying neo4j index?
Any thoughts?
Thanks

Here's a theory: I don't know if this is only an issue with the code pasted here but the check:
if (graphDb.index().existsForNodes("NODEINDEX"))
checks for the index named "NODEINDEX", however the actual query
graphDb.index().forNodes(NODEINDEX).query(query);
checks for the index named whatever is in the constant NODEINDEX. Those two are probably not the same and so it tries to create that index for you and fails due to not being in a transaction.

if there isn't an existing appropriate index, I think it'll create one before returning it; this operation needs to be wrapped in a transaction.

Related

Transaction Block has wrong Return [duplicate]

I have a problem with transactions. The data in the transaction is always null and the update handler is called only singe once. The documentation says :
To accomplish this, you pass transaction() an update function which is
used to transform the current value into a new value. If another
client writes to the location before your new value is successfully
written, your update function will be called again with the new
current value, and the write will be retried. This will happen
repeatedly until your write succeeds without conflict or you abort the
transaction by not returning a value from your update function
Now I know that there is no other client accessing the location right now. Secondly if I read the documentation correctly the updateCounters function should be called multiple times should it fail to retrieve and update data.
The other thing - if I take out the condition if (counters === null) the execution will fail as counters is null but on a subsequent attempt the transaction finishes fine - retrieves data and does the update.
simple once - set on this location work just fine but it is not safe.
Please what do I miss?
here is the code
self.myRef.child('counters')
.transaction(function updateCounters(counters){
if (counters === null) {
return;
}
else {
console.log('in transaction counters:', counters);
counters.comments = counters.comments + 1;
return counters;
}
}, function(error, committed, ss){
if (error) {
console.log('transaction aborted');
// TODO error handling
} else if (!committed){
console.log('counters are null - why?');
} else {
console.log('counter increased',ss.val());
}
}, true);
here is the data in the location
counters:{
comments: 1,
alerts: 3,
...
}
By returning undefined in your if( ... === null ) block, you are aborting the transaction. Thus it never sends an attempt to the server, never realizes the locally cached value is not the same as remote, and never retries with the updated value (the actual value from the server).
This is confirmed by the fact that committed is false and the error is null in your success function, which occurs if the transaction is aborted.
Transactions work as follows:
pass the locally cached value into the processing function, if you have never fetched this data from the server, then the locally cached value is null (the most likely remote value for that path)
get the return value from the processing function, if that value is undefined abort the transaction, otherwise, create a hash of the current value (null) and pass that and the new value (returned by processing function) to the server
if the local hash matches the server's current hash, the change is applied and the server returns a success result
if the server transaction is not applied, server returns the new value, client then calls the processing function again with the updated value from the server until successful
when ultimately successful, and unrecoverable error occurs, or the transaction is aborted (by returning undefined from the processing function) then the success method is called with the results.
So to make this work, obviously you can't abort the transaction on the first returned value.
One workaround to accomplish the same result--although it is coupled and not as performant or appropriate as just using the transactions as designed--would be to wrap the transaction in a once('value', ...) callback, which would ensure it's cached locally before running the transaction.

Update a Node object with Spring data

I want to update an existent Node in the db.
I could correctly create a node but can't update an existent one.
try (Transaction tx = template.getGraphDatabaseService().beginTx()) {
Node node = repository.findNodeUsingId("n1");
if(node != null){
//Modify some properties using setProperty
node.setProperty("name","P");
//How should I do to save the modified node object?
}else{
//Create the node
//This part works fine
node = template.createNode();
node.setProperty("name", "T");
}
tx.success();
}
You don't have to save the modified object.
Once setProperty has been called, your node property has been set in the current Transaction.
The only thing you are missing here is to close the Transaction, check this (from Neo4j Javadoc) about Transaction.close():
Commits or marks this transaction for rollback, depending on whether
success() or failure() has been previously invoked. All
ResourceIterables that where returned from operations executed inside
this transaction will be automatically closed by this method. This
method comes from AutoCloseable so that a Transaction can participate
in try-with-resource statements. It will not throw any declared
exception. Invoking this method (which is unnecessary when in
try-with-resource statement) or finish() has the exact same effect.

Unable to delete 15k+ nodes using neo4jclient

I am writing a Windows console application in C# that is supposed to import 15k nodes from an XML file and build a graph database in Neo4j (2.0.0) using the neo4jclient.
At the very beginning of the app, I am trying to remove all nodes and relationships from the database so that at every run of the application the database is fresh and clean:
Console.WriteLine("Deleting nodes and relationships...");
graphClient.Cypher.OptionalMatch("n-[r]-()").Delete("r").ExecuteWithoutResults();
graphClient.Cypher.Match("n").Delete("n").ExecuteWithoutResults();
Console.WriteLine("...done!");
At the moment the database has about 16k nodes (with no relationships between them) which were created by a couple of previous run of the application itself. When the second Delete statement above runs, this exception is thrown after 30 or so second:
Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.Threading.Tasks.TaskCanceledException: A task was canceled.
--- End of inner exception stack trace ---
at Neo4jClient.GraphClient.SendHttpRequest(HttpRequestMessage request, String commandDescription, HttpStatusCode[] expectedStatusCodes) in c:\TeamCity\buildAgent\work\5bae2aa9bce99f44\Neo4jClient\GraphClient.cs:line 138
at Neo4jClient.GraphClient.Neo4jClient.IRawGraphClient.ExecuteCypher(CypherQuery query) in c:\TeamCity\buildAgent\work\5bae2aa9bce99f44\Neo4jClient\GraphClient.cs:line 843
at Neo4jClient.Cypher.CypherFluentQuery.ExecuteWithoutResults() in c:\TeamCity\buildAgent\work\5bae2aa9bce99f44\Neo4jClient\Cypher\CypherFluentQuery.cs:line 322
at Xml2Cypher.Program.Main(String[] args) in c:\_PrivateProjects\KanjiDoc2Neo4J\Xml2Cypher\Program.cs:line 25
I also tried batching the delete statements using a Limit statement, but I get the same exception. Any ideas? I think the Request is timing out, but even batching doesn't seem to solve the issue.
graphClient.Cypher.Match("n").With("n").Limit(100).Delete("n").ExecuteWithoutResults();
I tried running the following statement from the browser:
match (n:Characters) with n limit 100 delete n
but even there I get an "unknown error".
Just increase the http timeout in neo4jclient then it should work.
The error you get in browser is wrong. It should say: "node has still relationships"
the query for deletes is:
MATCH (n)
OPTIONAL MATCH (n)-[r]->()
DELETE n,r
If you have many rels to delete you probably want to batch it. Unfortunately the promising PERIODIC COMMIT was limited to LOAD CSV after 2.1-M01 :(
So you're back to batching yourself (delete a block of 5k nodes and their rels)
MATCH (n)
LIMIT 5000
OPTIONAL MATCH (n)-[r]->()
DELETE n,r
RETURN count(*)
repeat until it returns 0.
You could also stop your Windows service, delete the graph.db folder, and restart the service. I have used this to completely "refresh" the database as it will create a new database. Something like this should work:
public static void Main(string[] args)
{
RefreshDatabase();
}
private static void RefreshDatabase()
{
ServiceController sc = new ServiceController("Neo4j Graph Database", "computername");
if (sc.Status != ServiceControllerStatus.Stopped)
sc.Stop();
Console.WriteLine("Stopping Neo4j Graph Database service...");
//sc.WaitForStatus(ServiceControllerStatus.Stopped);
Console.WriteLine("Neo4j Graph Database service stopped.\n");
Console.WriteLine("Deleting graph.db files and folders...\n");
RecursiveDelete(#"C:\neo4j-community-2.0.1\data\graph.db");
Console.WriteLine("Finished deleting graph.db folder contents.\n");
Console.WriteLine("Starting Neo4j Graph Database service...\n");
sc.Start();
//sc.WaitForStatus(ServiceControllerStatus.Running);
Console.WriteLine("Neo4j Graph Database running.\n");
}
private static void RecursiveDelete(string path)
{
DirectoryInfo di = new DirectoryInfo(path);
foreach (FileInfo file in di.GetFiles())
{
file.Delete();
}
foreach (DirectoryInfo directory in di.GetDirectories())
{
directory.Delete(true);
}
}

Cannot access nodes created using java in neo4j database, neo4j-server.properties issues

I am able to create nodes and relationships through Java on a Neo4j database. When I try to access the created nodes in the next run I get this error:
Exception in thread "main" org.neo4j.graphdb.NotFoundException: Node 27 not found
In webadmin interface the dashboard shows the number of nodes/relationships created through Java, but when I issue this query: START n=node(*) RETURN n; I get only 1 node in the ouput.
(FYI I have installed Ne04j in my windows machine(local) and using embedded database java code to create nodes.)
Java code I used to connect to db:
final String dbpath = "C:\\neo4j-community-1.9.4\\data\\graph.db";
GraphDatabaseService graphdb = new GraphDatabaseFactory().newEmbeddedDatabase(dbpath);
The settings I have used in ne04j-server.properties are:
org.neo4j.server.database.location=/C:/neo4j-community-1.9.4/data/graph.db/
org.neo4j.server.webserver.https.keystore.location=data/keystore
org.neo4j.server.webadmin.rrdb.location=data/rrd
org.neo4j.server.webadmin.data.uri=/C:/neo4j-community-1.9.4/data/graph.db/
org.neo4j.server.webadmin.management.uri=/db/manage/
When I create node through Java the data/keystore file does not get populated, and only gets populated when creating a node through webadmin interface. Changing the path of keystore file to absolute path also did not work.
Can anybody point the mistake in this scenario, Thanks .
The problem was the nodes created were not comitted. To commit the nodes we got to give finish() :
try{
Transaction tx = graphdb.beginTx();
final String dbpath = "/C:/neo4j-community-1.9.4/data/graph.db/";
GraphDatabaseService graphdb = new GraphDatabaseFactory().newEmbeddedDatabase(dbpath);
Node n1 = graphdb.createNode();
n1.setProperty("type", "company");
n1.setProperty("location", "india");
....
...
}} catch(Exception e){
tx.failure();
} finally {
tx.success();
**tx.finish();**
}
Ranjith's answer was correct until recently, but tx.finish() has now been deprecated.
tx.close(); is now the correct way to commit or rollback the transaction - it will do one or the other depending on whether you've previously called tx.success().
They changed this so the transaction is autocloseable in a try with resources block.
Have you tried:
String dbpath = "C:/neo4j-community-1.9.4/data/graph.db";

Neo4j : When Query using an index hint , I got Unknown error

I use the exactly query just as http://docs.neo4j.org/chunked/milestone/query-using.html says.
My Neo4j Kernel version is
Neo4j - Graph Database Kernel 2.0.0-M03
I don't know why?
It's ok for me to run
CREATE (_1 { `name`:"Emil" })
CREATE (_2:`German` { `name`:"Stefan", `surname`:"Plantikow" })
CREATE (_3 { `age`:34, `name`:"Peter" })
CREATE (_4:`Swedish` { `age`:36, `awesome`:true, `name`:"Andres", `surname`:"Taylor" })
CREATE _1-[:`KNOWS`]->_3
CREATE _2-[:`KNOWS`]->_4
CREATE _4-[:`KNOWS`]->_3
But I got Unknown error while using
match n:Swedish using index n:Swedish(surname)
where n.surname = 'Taylor'
return n
If your query explicitly mandates to use an index, you need to make sure that it exists.
So run before querying:
CREATE INDEX ON :Swedish(surname)

Resources