我们一直在想,使用Neo4j 2.0,同时查询和删除节点将不再抛出NotFoundException。我们之前使用Neo4j 1.9.3的系统充满了检查来处理这个异常(非常难看的代码)。 有没有更好的方法来处理neo4j 2.0中的NotFoundException(如果没有消除),或者在管道中?
堆栈追踪:
org.neo4j.graphdb.NotFoundException: Node 2432 not found
at org.neo4j.kernel.impl.core.NodeManager.getNodeForProxy(NodeManager.java:425)
at org.neo4j.kernel.impl.api.state.OldTxStateBridgeImpl.deleteNode(OldTxStateBridgeImpl.java:111)
at org.neo4j.kernel.impl.api.state.TxStateImpl.nodeDoDelete(TxStateImpl.java:250)
at org.neo4j.kernel.impl.api.StateHandlingStatementOperations.nodeDelete(StateHandlingStatementOperations.java:100)
at org.neo4j.kernel.impl.api.ConstraintEnforcingEntityOperations.nodeDelete(ConstraintEnforcingEntityOperations.java:140)
at org.neo4j.kernel.impl.api.LockingStatementOperations.nodeDelete(LockingStatementOperations.java:196)
at org.neo4j.kernel.impl.api.OperationsFacade.nodeDelete(OperationsFacade.java:428)
at org.neo4j.cypher.internal.spi.v2_0.TransactionBoundExecutionContext$NodeOperations.delete(TransactionBoundExecutionContext.scala:132)
at org.neo4j.cypher.internal.spi.v2_0.TransactionBoundExecutionContext$NodeOperations.delete(TransactionBoundExecutionContext.scala:130)
at org.neo4j.cypher.internal.compiler.v2_0.spi.DelegatingOperations.delete(DelegatingQueryContext.scala:92)
at org.neo4j.cypher.internal.compiler.v2_0.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations.org$neo4j$cypher$internal$compiler$v2_0$spi$ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$super$delete(ExceptionTranslatingQueryContext.scala:118)
at org.neo4j.cypher.internal.compiler.v2_0.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply$mcV$sp(ExceptionTranslatingQueryContext.scala:118)
at org.neo4j.cypher.internal.compiler.v2_0.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply(ExceptionTranslatingQueryContext.scala:118)
at org.neo4j.cypher.internal.compiler.v2_0.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply(ExceptionTranslatingQueryContext.scala:118)
at org.neo4j.cypher.internal.compiler.v2_0.spi.ExceptionTranslatingQueryContext.org$neo4j$cypher$internal$compiler$v2_0$spi$ExceptionTranslatingQueryContext$$translateException(ExceptionTranslatingQueryContext.scala:149)
at org.neo4j.cypher.internal.compiler.v2_0.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations.delete(ExceptionTranslatingQueryContext.scala:118)
at org.neo4j.cypher.internal.compiler.v2_0.spi.UpdateCountingQueryContext$CountingOps.delete(UpdateCountingQueryContext.scala:118)
at org.neo4j.cypher.internal.compiler.v2_0.mutation.DeleteEntityAction.org$neo4j$cypher$internal$compiler$v2_0$mutation$DeleteEntityAction$$delete(DeleteEntityAction.scala:50)
at org.neo4j.cypher.internal.compiler.v2_0.mutation.DeleteEntityAction.exec(DeleteEntityAction.scala:36)
at org.neo4j.cypher.internal.compiler.v2_0.pipes.ExecuteUpdateCommandsPipe.org$neo4j$cypher$internal$compiler$v2_0$pipes$ExecuteUpdateCommandsPipe$$exec(ExecuteUpdateCommandsPipe.scala:56)
at org.neo4j.cypher.internal.compiler.v2_0.pipes.ExecuteUpdateCommandsPipe$$anonfun$org$neo4j$cypher$internal$compiler$v2_0$pipes$ExecuteUpdateCommandsPipe$$executeMutationCommands$1$$anonfun$apply$2.apply(ExecuteUpdateCommandsPipe.scala:45)
at org.neo4j.cypher.internal.compiler.v2_0.pipes.ExecuteUpdateCommandsPipe$$anonfun$org$neo4j$cypher$internal$compiler$v2_0$pipes$ExecuteUpdateCommandsPipe$$executeMutationCommands$1$$anonfun$apply$2.apply(ExecuteUpdateCommandsPipe.scala:45)
at scala.collection.Iterator$$anon$13.hasNext(Iterator.scala:371)
at scala.collection.Iterator$$anon$13.hasNext(Iterator.scala:371)
at org.neo4j.cypher.internal.compiler.v2_0.pipes.EmptyResultPipe.internalCreateResults(EmptyResultPipe.scala:28)
at org.neo4j.cypher.internal.compiler.v2_0.pipes.PipeWithSource.createResults(Pipe.scala:71)
at org.neo4j.cypher.internal.compiler.v2_0.executionplan.ExecutionPlanBuilder.org$neo4j$cypher$internal$compiler$v2_0$executionplan$ExecutionPlanBuilder$$prepareStateAndResult(ExecutionPlanBuilder.scala:149)
at org.neo4j.cypher.internal.compiler.v2_0.executionplan.ExecutionPlanBuilder$$anonfun$3.apply(ExecutionPlanBuilder.scala:136)
at org.neo4j.cypher.internal.compiler.v2_0.executionplan.ExecutionPlanBuilder$$anonfun$3.apply(ExecutionPlanBuilder.scala:135)
at org.neo4j.cypher.internal.compiler.v2_0.executionplan.ExecutionPlanBuilder$$anon$6.execute(ExecutionPlanBuilder.scala:50)
at org.neo4j.cypher.internal.ExecutionPlanWrapperForV2_0.execute(CypherCompiler.scala:93)
at org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:61)
at org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:55)
at org.neo4j.cypher.javacompat.ExecutionEngine.execute(ExecutionEngine.java:65)
at net.ahm.graph.ConcurrDeleteLab$1.run(ConcurrDeleteLab.java:65)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744
模拟问题的源代码:
package net.ahm.graph;
import java.io.File;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;
import org.neo4j.cypher.javacompat.ExecutionEngine;
import org.neo4j.cypher.javacompat.ExecutionResult;
import org.neo4j.graphdb.DynamicLabel;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.graphdb.schema.IndexDefinition;
import org.neo4j.graphdb.schema.Schema;
import org.neo4j.kernel.impl.util.FileUtils;
import org.neo4j.kernel.impl.util.StringLogger;
public class ConcurrDeleteLab {
private static final Logger LOG = Logger.getLogger(CypherLab.class);
private final static int CONCURRENCY = 4;
public static void main(String[] args) throws Exception {
FileUtils.deleteRecursively(new File("graphdb"));
final GraphDatabaseService graphDb = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder("graphdb")
.setConfig(GraphDatabaseSettings.use_memory_mapped_buffers, "true").setConfig(GraphDatabaseSettings.cache_type, "strong")
.newGraphDatabase();
registerShutdownHook(graphDb);
LOG.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>> NUMBER OF PARALLEL CYPHERS: " + CONCURRENCY);
LOG.info(">>>> STARTED GRAPHDB");
createIndex("Entity", "name", graphDb);
try (Transaction tx = graphDb.beginTx()) {
for (int i = 0; i < 100000; i++) {
Node child = graphDb.createNode(DynamicLabel.label("Entity"));
child.setProperty("name", "entity" + i);
}
tx.success();
}
LOG.info(">>>> CREATED NODES");
final ExecutionEngine engine = new ExecutionEngine(graphDb, StringLogger.SYSTEM);
for (int i = 0; i < 4; i++) {
try (Transaction tx = graphDb.beginTx()) {
ExecutionResult result = engine.execute("match (n:Entity) return n.name");
for (Map<String, Object> row : result) {
assert ((String) row.get("n.name") != null);
}
tx.success();
}
}
LOG.info(">>>> WARMED UP");
ExecutorService es = Executors.newFixedThreadPool(CONCURRENCY);
final CountDownLatch cdl = new CountDownLatch(CONCURRENCY);
for (int i = 0; i < CONCURRENCY; i++) {
if (i % 2 == 0) {
es.execute(new Runnable() {
@Override
public void run() {
try (Transaction tx = graphDb.beginTx()) {
long time = System.currentTimeMillis();
engine.execute("match (n:Entity) delete n");
LOG.info(">>>> CYPHER TOOK: " + (System.currentTimeMillis() - time) + " m-secs");
tx.success();
} catch (Throwable t) {
LOG.error(t);
t.printStackTrace();
} finally {
cdl.countDown();
}
}
});
} else {
es.execute(new Runnable() {
@Override
public void run() {
try (Transaction tx = graphDb.beginTx()) {
long time = System.currentTimeMillis();
ExecutionResult result = engine.execute("match (n:Entity) return n.name");
LOG.info(">>>> CYPHER TOOK: " + (System.currentTimeMillis() - time) + " m-secs");
int count = 0;
time = System.currentTimeMillis();
for (Map<String, Object> row : result) {
assert ((String) row.get("n.name") != null);
count++;
}
LOG.info(">>>> GETTING RESULTS TOOK: " + (System.currentTimeMillis() - time) + " m-secs");
tx.success();
LOG.info(">>>> CYPHER RETURNED ROWS: " + count);
} catch (Throwable t) {
LOG.error(t);
t.printStackTrace();
} finally {
cdl.countDown();
}
}
});
}
}
cdl.await();
es.shutdown();
}
private static void createIndex(String label, String propertyName, GraphDatabaseService graphDb) {
IndexDefinition indexDefinition;
try (Transaction tx = graphDb.beginTx()) {
Schema schema = graphDb.schema();
indexDefinition = schema.indexFor(DynamicLabel.label(label)).on(propertyName).create();
tx.success();
}
try (Transaction tx = graphDb.beginTx()) {
Schema schema = graphDb.schema();
schema.awaitIndexOnline(indexDefinition, 10, TimeUnit.SECONDS);
tx.success();
}
}
private static void registerShutdownHook(final GraphDatabaseService graphDb) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
LOG.info("### GRAPHDB SHUTDOWNHOOK INVOKED !!!");
graphDb.shutdown();
}
});
}
}