Giter Site home page Giter Site logo

neo4j-java-driver's Introduction

Neo4j Java Driver

This repository holds the official Java Driver for Neo4j.

It works with both single instance and clustered databases.

Network communication is handled using Bolt Protocol.

Versioning

Starting with 5.0, the Neo4j Drivers will be moving to a monthly release cadence. A minor version will be released on the last Friday of each month so as to maintain versioning consistency with the core product (Neo4j DBMS) which has also moved to a monthly cadence.

As a policy, patch versions will not be released except on rare occasions. Bug fixes and updates will go into the latest minor version and users should upgrade to that. Driver upgrades within a major version will never contain breaking API changes.

Supported Driver Series

Driver Series Supported Java Runtime versions Status Changelog
5.x 17 Primary development branch. link
4.4 8, 11 Maintenance. link

Server Compatibility

The compatibility with Neo4j Server versions is documented in the Neo4j Knowledge Base.

Preview features

The preview feature is a new feature that is a candidate for a future GA status.

It enables users to try the feature out and maintainers to refine and update it.

The preview features are not considered to be experimental, temporary or unstable.

However, they may change more rapidly, without following the usual deprecation cycle.

Most preview features are expected to be granted the GA status unless some unexpected conditions arise.

Due to the increased flexibility of the preview status, user feedback is encouraged so that it can be considered before the GA status.

Every feature gets a dedicated GitHub Discussion where feedback may be shared.

Usage

This section provides general information for engineers who are building Neo4j-backed applications.

The pom.xml file

The driver is distributed exclusively via Maven. To use the driver in your Maven project, include the following within your pom.xml file:

<dependency>
    <groupId>org.neo4j.driver</groupId>
    <artifactId>neo4j-java-driver</artifactId>
    <version>x.y.z</version>
</dependency>

Here, x.y.z will need to be replaced with the appropriate driver version. It is generally recommended to use the latest driver version wherever possible. This ensures access to new features and recent bug fixes. All available versions of this driver can be found at Maven Central or Releases.

Java Platform Module System

Both neo4j-java-driver and neo4j-java-driver-all artifacts have org.neo4j.driver module name.

Starting from version 5.0 the neo4j-java-driver includes an explicit module declaration (module-info.java).

The neo4j-java-driver-all includes an explicit module declaration (module-info.java) starting from version 5.7.

Example

To run a simple query, the following can be used:

var authToken = AuthTokens.basic("neo4j", "password");
try (var driver = GraphDatabase.driver("bolt://localhost:7687", authToken)) {
    var result = driver.executableQuery("CREATE (n)").execute();
    System.out.println(result.summary().counters().nodesCreated());
}

For full applications, a single Driver object should be created with application-wide scope and lifetime. This allows full utilization of the driver connection pool. The connection pool reduces network overhead added by sharing TCP connections between subsequent transactions. Network connections are acquired on demand from the pool when running Cypher queries, and returned back to connection pool after query execution finishes. As a result of this design, it is expensive to create and close a Driver object. Session objects, on the other hand, are very cheap to use.

Thread Safety

Driver objects are thread-safe, but Session and Transaction objects should only be used by a single thread.

Further reading

Check out our Wiki for detailed and most up-to-date manuals, driver API documentations, changelogs, etc.

Bug Report

If you encounter any bugs while using this driver, please follow the instructions in our Contribution Guide when raising an issue at Issues.

When reporting, please mention the versions of the driver and server, as well as the server topology (single instance, causal cluster, etc). Also include any error stacktraces and a code snippet to reproduce the error if possible, as well as anything else that you think might be helpful.

For Driver Engineers

This section targets users who would like to compile the driver source code on their own machine for the purpose of, for example, contributing a PR. Before contributing to this project, please take a few minutes to read our Contribution Guide.

Java Version

For the 1.5+ Driver Series, the source code must compile on Java 8.

For the previous versions, the compilation requires Java 7.

Building

The source code here reflects the current development status of a new driver version.

To use the driver in a project, please use the released driver via Maven Central or check out the code with git tags of corresponding versions instead.

Running Tests and Creating a Package

The following command may be used to unit test and install artifacts without running integration tests:

mvn clean install -DskipITs -P skip-testkit

Integration tests have the following prerequisites:

Testkit that is a tooling that is used to run integration tests for all official Neo4j drivers. It can be executed using Docker during Maven build and in such case does not require additional setup. See the instructions below for more details.

There are 2 ways of running Testkit tests:

  1. Using the testkit-tests module of this project.
  2. Manually cloning Testkit and running it directly.
Using the testkit-tests module

The testkit-tests module will automatically check out Testkit and run it during Maven build.

Prerequisites:

  • Docker
  • /var/run/docker.sock available to be passed through to running containers. This is required because Testkit needs access to Docker in order to launch additional containers.
  • The driver project location must be sharable with Docker containers as Testkit container needs to have access to it.

Make sure to run build for the whole project and not just for testkit-tests module. Sample commands:

  • mvn clean verify - runs all tests.
  • mvn clean verify -DskipTests - skips all tests.
  • mvn clean verify -DtestkitArgs='--tests STUB_TESTS' - runs all project tests and Testkit stub tests.
  • mvn clean verify -DskipTests -P testkit-tests - skips all project tests and runs Testkit tests.
  • mvn clean verify -DskipTests -DtestkitArgs='--tests STUB_TESTS' - skips all project tests and runs Testkit stub tests.
  • mvn clean verify -DskipITs -DtestkitArgs='--tests STUB_TESTS' - skips all integration tests and runs Testkit stub tests.
  • mvn clean verify -DskipTests -DtestkitArgs='--run-only-selected tests.neo4j.test_session_run.TestSessionRun.test_can_return_path --configs 4.4-enterprise-neo4j' - skips all project tests and runs selected Testkit test on specific configuration.

If you interrupt Maven build, you have to remove Testkit containers manually.

Running Testkit manually

Prerequisites:

  • Docker
  • Python3
  • Git

Clone Testkit and run as follows:

git clone [email protected]:neo4j/neo4j-java-driver.git 
git clone [email protected]:neo4j-drivers/testkit.git
cd testkit
TEST_DRIVER_NAME=java \
TEST_DRIVER_REPO=`realpath ../neo4j-java-driver` \
TEST_DOCKER_RMI=true \
python3 main.py --tests UNIT_TESTS --configs 4.3-enterprise

To run additional Testkit test, specify TESTKIT_TESTS:

TEST_DRIVER_NAME=java \
TEST_DRIVER_REPO=`realpath ../neo4j-java-driver` \
TEST_DOCKER_RMI=true \
python3 main.py --tests TESTKIT_TESTS UNIT_TESTS --configs 4.3-enterprise

On Windows or in the absence of a Bash-compatible environment, the required steps are probably different. A simple mvn clean install will require admin rights on Windows, because our integration tests require admin privileges to install and start a service.

If all of this fails and you only want to try out a local development version of the driver, you could skip all tests like this:

mvn clean install -DskipTests

neo4j-java-driver's People

Contributors

ali-ince avatar azzazzel avatar bigmontz avatar boggle avatar crystalmethod avatar dotstart avatar fbiville avatar gjmwoods avatar gurkerl83 avatar injectives avatar jakewins avatar jjaderberg avatar jsoref avatar lutovich avatar martin-neotech avatar michael-simons avatar mneedham avatar nigelsmall avatar nikarh avatar petrjanouch avatar pontusmelke avatar praveenag avatar ragnarw avatar robsdedude avatar sarmbruster avatar stefano-ottolenghi avatar technige avatar thelonelyvulpes avatar thobe avatar zhenlineo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

neo4j-java-driver's Issues

Error 500 java.nio.channels.SocketChannel is a restricted class. Please see the Google App Engine developer's guide for more details.

Hi,
I am trying out an example from README page.
Here is my code

public class HelloServlet extends HttpServlet {

    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        PrintWriter out = resp.getWriter();
        Driver driver = GraphDatabase.driver( "bolt://localhost:7687", AuthTokens.basic( "xxxxx", "xxxx" ) );
        Session session = driver.session();
        Transaction tx = session.beginTransaction();

        tx.run("MERGE (a:Person {name: {x}})", parameters("x", "ABC"));
        tx.success();  // Mark this write as successful.

        out.println("Welcome to Neo4j Bolt Driver implementation ..");

        session.close();
        driver.close();
        // out.println("Hello, this is my world");
    }
}

I get the following error: - I was wondering if someone could help me on this. Thanks !

HTTP ERROR 500

Problem accessing /. Reason:

        <pre>    java.nio.channels.SocketChannel is a restricted class. Please see the Google  App Engine developer's guide for more details.</pre>
    </p>
    <h3>Caused by:</h3>
    <pre>java.lang.NoClassDefFoundError: java.nio.channels.SocketChannel is a restricted class. Please see the Google  App Engine developer's guide for more details.
at com.google.appengine.tools.development.agent.runtime.Runtime.reject(Runtime.java:50)
at org.neo4j.driver.internal.net.ChannelFactory.create(ChannelFactory.java:38)
at org.neo4j.driver.internal.net.SocketClient.start(SocketClient.java:124)
at org.neo4j.driver.internal.net.SocketConnection.startSocketClient(SocketConnection.java:92)
at org.neo4j.driver.internal.net.SocketConnection.&lt;init&gt;(SocketConnection.java:67)
at org.neo4j.driver.internal.net.SocketConnector.createConnection(SocketConnector.java:77)
at org.neo4j.driver.internal.net.SocketConnector.connect(SocketConnector.java:50)
at org.neo4j.driver.internal.net.pooling.SocketConnectionPool$ConnectionSupplier.get(SocketConnectionPool.java:204)
at org.neo4j.driver.internal.net.pooling.SocketConnectionPool$ConnectionSupplier.get(SocketConnectionPool.java:186)
at org.neo4j.driver.internal.net.pooling.BlockingPooledConnectionQueue.acquire(BlockingPooledConnectionQueue.java:96)
at org.neo4j.driver.internal.net.pooling.SocketConnectionPool.acquireConnection(SocketConnectionPool.java:137)
at org.neo4j.driver.internal.net.pooling.SocketConnectionPool.acquire(SocketConnectionPool.java:76)
at org.neo4j.driver.internal.DirectConnectionProvider.acquireConnection(DirectConnectionProvider.java:45)
at org.neo4j.driver.internal.NetworkSession.acquireConnection(NetworkSession.java:340)
at org.neo4j.driver.internal.NetworkSession.beginTransaction(NetworkSession.java:288)
at org.neo4j.driver.internal.NetworkSession.beginTransaction(NetworkSession.java:175)
at introduction.HelloServlet.doGet(HelloServlet.java:37)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
at com.google.appengine.api.socket.dev.DevSocketFilter.doFilter(DevSocketFilter.java:74)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.ResponseRewriterFilter.doFilter(ResponseRewriterFilter.java:134)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:34)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:63)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:48)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:122)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectRequest(DevAppServerModulesFilter.java:366)
at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectModuleRequest(DevAppServerModulesFilter.java:349)
at com.google.appengine.tools.development.DevAppServerModulesFilter.doFilter(DevAppServerModulesFilter.java:116)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:95)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:508)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:547)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)

No explicit Transaction Timeout setting

There may be cases when an application request should be timed out by the client if it takes longer than a certain number of seconds. The Java driver has no means to specify a request/transaction timeout parameter, and it doesn't appear to honour the server property dbms.transaction_timeout either.

Value Types are lost after sending data over the driver

Value Types (Integer and Float) are lost after sending data over the driver,

If I create Node with 4 properties:

  • int : 1
  • long : 2L
  • double : 3.0
  • float : 4.0f
    I would expect same property types to be returned when retrieved from the server via driver.

Neo4j Version: 3.1
Operating System: Win7
API: neo4j-java-driver 1.1.0

Steps to reproduce

  1. Create Node
  2. Assign 4 properties of different types (int, long, double, float)
  3. Retrieve each value and evaluate it's type against the initial type

Expected behavior

property creation type is equal to retrieved property type.

Actual behavior

int type is retrieved as long
float type is retrieved as double

Findings

Well, I can see you've got 'value adapter' for IntegerValue which in reality combines two types - long and int, and FloatValue - both of which extend NumberValueAdapter.
When I've created Node and am setting properties - it goes through Values.value(propertyValue) and transforms my Integer into:

    private final long val;
    public IntegerValue( long val ) {
        this.val = val;
    }

and Float into:

    private final double val;
    public FloatValue( double val ) {
        this.val = val;
    }

This makes me sad. So On the server I end up always only persisting long and double typed properties, never int or float.
When I retrieve this properties from the server using Node.asMap() -> I again (not surprised) get back IntegerValue and FloatValue which are "transformed" (just returns their val) via NumberValueAdapter.asObject() -> asNumber(); respectively into Long and Double.

What is important - this is not compatible with Official Embedded DB and REST

Result fieldNames() empty after execution (fieldNames Map getting replaced)

Hello,
I created a Node with the following statement

CREATE (n:TestNode {name:'test'}) RETURN n;

When trying to retrieve the current Record's fieldNames, the result is empty.

Driver driver = GraphDatabase.driver( "neo4j://localhost" );    
Session session = driver.session();
Result rs = session.run("MATCH (n:TestNode) RETURN n;"); 
System.out.println(rs.fieldNames());

I saw Issue #27 describing a similar problem and did some debugging.

I set a breakpoint within the SocketResponseHandler's handleSuccessMessage function and noticed that the collector's (in this case an instance of ResultBuilder) fieldNames Map gets filled with the correct fieldNames, but then another SUCCESS message comes in (within the same execution of session.run(...)) and replaces the Map containing the fieldNames with an empty Map, since that SUCCESS message had no field names attached and thus triggers the replacement.

public void fieldNames( String[] names )
{
    if ( names.length == 0 )
    {
        fieldLookup = Collections.EMPTY_MAP;
    }
...

The problem can also be illustrated through this example of a typical exchange by Nigel Small

 Client: RUN "MATCH (a:Person) RETURN a.name AS name, a.age AS age" {}
 Client: PULL_ALL
 Server: SUCCESS {"fields": ["name", "age"]} <---- fieldNames get set
 Server: RECORD ["Alice", 33]
 Server: RECORD ["Bob", 44]
 Server: RECORD ["Carol", 55]
 Server: SUCCESS {} <----- fieldNames get replaced with an empty map

As pointed out in Issue #27, the field names only get sent in one SUCCESS message, so my question is whether this replacement is intended or a bug.
If it is intended, is there a way to address stream's current Record object directly instead of using the fieldNames()/get() functions and how would fieldNames() be used, if it is empty after a succesful exchange?

I am looking foward to a reply and would be grateful for any kind of hints or suggestions.

Kind regards,
Christian Kramp

Failed to enlarge network buffer still occurring in 1.1.2

We continue to see Issue #177 running v1.1.2:

org.neo4j.driver.v1.exceptions.ClientException: Failed to enlarge network buffer from 16921 to 16921. This is either because the new size is however less than the old size, or because the application buffer size 8192 is so big that the application data still cannot fit into the new network buffer.

We are using the neo4j driver in a Scala v2.11 app with Neo4j Enterprise Edition v3.0.4.

Please let me know what more information I can provide to help troubleshoot or diagnose this issue.

Make driver fail fast algorithm configurable

This commit has the side effect that any attempt to create a SessionFactory requires a Neo4J server running.

This is a problem in Spring Boot (specifically for the integration tests) as we don't need to actually access to Neo4j but would like to validate other pieces of the configuration. I also think this can be surprising for users when they upgrade.

Can you make this behaviour configurable somehow?

BoltServerAddress throwing exception for bolt address from neo4j documentation

I don't know if this is the correct place for this, as it touches neo4j-java-driver and neo4j-bolt, so if this is the wrong place, thanks for kindly pointing me in the correct direction!


I cant get the Bolt connector to work as described in https://neo4j.com/docs/java-reference/current/#tutorials-java-embedded-bolt

When using .setConfig( bolt.address, "localhost:7687");, the following exception is thrown (tested with neo4j-java-driver-1.2.1 and neo4j-java-driver-1.3.0-rc1 )

Invalid URI format `localhost:7689`
java.lang.IllegalArgumentException
    at org.neo4j.driver.internal.net.BoltServerAddress.from(BoltServerAddress.java:47)
    at org.neo4j.driver.internal.DriverFactory.newInstance(DriverFactory.java:57)
    at org.neo4j.driver.v1.GraphDatabase.driver(GraphDatabase.java:132)
    at org.neo4j.driver.v1.GraphDatabase.driver(GraphDatabase.java:114)
    at org.structr.bolt.BoltDatabaseService.initialize(BoltDatabaseService.java:132)
    at org.structr.bolt.NodeWrapperTest.testDeleteException(NodeWrapperTest.java:56)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:45)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:123)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:104)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:164)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:110)
    at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:175)
    at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcessWhenForked(SurefireStarter.java:107)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:68)

The last working configuration was with bolt.address = "bolt://localhost:7689", neo4j-bolt-3.0.9 and neo4j-java-driver-1.2.1

From neo4j-bolt-3.0.9 to neo4j-bolt-3.1.0 a change was made to org.neo4j.bolt.transport.NettyServer in line 99, which (I think) causes this problem:

3.0.9

new ServerBootstrap()
        .[...]
        .bind( initializer.address().getHost(), initializer.address().getPort() )

3.1.0

new ServerBootstrap()
        .[...]
        .bind( initializer.address().socketAddress() )

When using our old bolt.address = "bolt://localhost:7689", this change leads to an exception because the InetSocketAddress created from this is unresolved.

When using the address from the example bolt.address = "localhost:7689", the created InetSocketAddress can be resolved but the aforementioned exception is thrown.

Do you have any advice for this?

byte[] types are not support by Bolt driver, but are supported by Neo4j native API

It seems that values of type byte are supported:

https://github.com/neo4j/neo4j-java-driver/blob/1.1/driver/src/main/java/org/neo4j/driver/v1/Values.java#L77

However, byte[] is not:

https://github.com/neo4j/neo4j-java-driver/blob/1.1/driver/src/main/java/org/neo4j/driver/v1/Values.java#L87

This is contrary to using the native GraphDatabaseService and the general statement that arrays of native of types are supported.

1.0.0-M02 cannot handle propery sizes over ~10Kb

I'm trying out Neo4j version 3.0.0-M02 using the neo4j-java-driver driver version 1.0.0-M02.

  1. I'm creating a node with a property with ~10Kb of data.
  2. When I retrieve the node the data has changed, but not the length.

If I create the node with smaller amount of data (~1Kb) it works as it should.

byte[] b = new byte[1000]; //works
byte[] b = new byte[7000]; //does not work
new Random().nextBytes(b);

sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
String data = encoder.encode(b);

Session session = GraphDatabase.driver("bolt://localhost").session();

String createQuery = "CREATE (a:Asset {" +
        "id : {id}," +
        "type : 'test'," +
        "created : {created}," +
        "data: {data}" +
        "}) RETURN a";

String id = UUID.randomUUID().toString();
long created = System.currentTimeMillis();

Map<String,Value> createValues = Values.parameters("id",id,"created",created,"data",data);

session.run(createQuery,createValues);

String matchQuery = "MATCH (a:Asset {id : {id}}) RETURN a.data as data";
Map<String,Value> matchValues = Values.parameters("id",id);

ResultCursor matchCursor = session.run(matchQuery,matchValues);

matchCursor.list().get(0).asMap().forEach((k,v) -> {
    Assert.assertEquals(data.length(),v.asString().length());
    Assert.assertEquals(data,v.asString());
});
session.close();

Values.parameters for Labels and Relationship types

Hello,

It seems it is not possible to use Values.parameters system for node labels or relationship types in the current version.

ex : MATCH (p:people:{contractor_type} {name:{name}})-[:{link_type}]->(something)
with contractor_type and link_type as parameters as well as name.

Could this be added as futur feature ?

Exception while executing statement with PROFILE and parameters

Driver version:

<dependency>
    <groupId>org.neo4j.driver</groupId>
    <artifactId>neo4j-java-driver</artifactId>
    <version>1.4.4</version>
</dependency>

Database version: ENTERPRISE EDITION 3.1.5

OS: Linux server.local 4.2.3-300.fc23.x86_64 #1 SMP Mon Oct 5 15:42:54 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

The following program throws an exception when the statement is executed with the PROFILE clause and parameters:

public static void main(String[] args) {
    //
    // CREATE (n:Test{values: ['T1','Other']})
    //
    // driver instance
    try (Driver driver = GraphDatabase.driver("bolt://localhost", AuthTokens.basic("neo4j", "neo4j"))) {
        // session
        try (Session session = driver.session()) {
            // transaction
            try (Transaction transaction = session.beginTransaction()) {
                // statement using PROFILE and NO parameter ==> OK
                // StatementResult statementResult = transaction.run("PROFILE MATCH (n:Test) WHERE (CASE WHEN ANY(x in n.values WHERE x =~ '^T-?\\\\d+$') THEN SUBSTRING(HEAD([x in n.values WHERE x =~ '^T-?\\\\d+$']), 1) ELSE '1' END = '1') RETURN ID(n) as C0 LIMIT 1");
                // statement using parameter ==> OK
                // StatementResult statementResult = transaction.run("MATCH (n:Test) WHERE (CASE WHEN ANY(x in n.values WHERE x =~ '^T-?\\\\d+$') THEN SUBSTRING(HEAD([x in n.values WHERE x =~ '^T-?\\\\d+$']), 1) ELSE '1' END = {p0}) RETURN ID(n) as C0 LIMIT 1", Collections.singletonMap("p0", "1"));
                // statement using PROFILE and parameter ==> FAIL
                StatementResult statementResult = transaction.run("PROFILE MATCH (n:Test) WHERE (CASE WHEN ANY(x in n.values WHERE x =~ '^T-?\\\\d+$') THEN SUBSTRING(HEAD([x in n.values WHERE x =~ '^T-?\\\\d+$']), 1) ELSE '1' END = {p0}) RETURN ID(n) as C0 LIMIT 1", Collections.singletonMap("p0", "1"));
                // loop results
                while (statementResult.hasNext()) {
                    // current record
                    Record record = statementResult.next();
                    // print record
                    System.out.println(record.get(0));
                }
                // process profile
                ResultSummary summary = statementResult.consume();
                if (summary.hasProfile()) {
                    // log information
                    System.out.println(summary.profile());
                }
                // commit
                transaction.success();
            }
        }
    }
}

Exception:

Exception in thread "main" org.neo4j.driver.v1.exceptions.DatabaseException: Illegal group reference
	at org.neo4j.driver.internal.net.SocketResponseHandler.handleFailureMessage(SocketResponseHandler.java:83)
	at org.neo4j.driver.internal.messaging.PackStreamMessageFormatV1$Reader.unpackFailureMessage(PackStreamMessageFormatV1.java:470)
	at org.neo4j.driver.internal.messaging.PackStreamMessageFormatV1$Reader.read(PackStreamMessageFormatV1.java:431)
	at org.neo4j.driver.internal.net.SocketClient.receiveOne(SocketClient.java:191)
	at org.neo4j.driver.internal.net.SocketConnection.receiveOne(SocketConnection.java:217)
	at org.neo4j.driver.internal.net.ConcurrencyGuardingConnection.receiveOne(ConcurrencyGuardingConnection.java:165)
	at org.neo4j.driver.internal.net.pooling.PooledSocketConnection.receiveOne(PooledSocketConnection.java:183)
	at org.neo4j.driver.internal.InternalStatementResult.receiveOne(InternalStatementResult.java:335)
	at org.neo4j.driver.internal.InternalStatementResult.tryFetchNext(InternalStatementResult.java:325)
	at org.neo4j.driver.internal.InternalStatementResult.hasNext(InternalStatementResult.java:193)
	at test.Program.main(Program.java:80)

Database log:

2017-10-10 15:52:49.584+0000 ERROR Client triggered an unexpected error [UnknownError]: Illegal group reference. See debug.log for more details, reference 7ad3067b-882e-49ca-83b1-ffc103712384.

Database debug.log:

2017-10-10 15:52:49.584+0000 ERROR [o.n.b.v.r.ErrorReporter] Client triggered an unexpected error [UnknownError]: Illegal group reference. See debug.log for more details, reference 7ad3067b-882e-49ca-83b1-ffc103712384.
2017-10-10 15:52:49.585+0000 ERROR [o.n.b.v.r.ErrorReporter] Client triggered an unexpected error [UnknownError]: Illegal group reference, reference 7ad3067b-882e-49ca-83b1-ffc103712384. Illegal group reference
java.lang.IllegalArgumentException: Illegal group reference
	at java.util.regex.Matcher.appendReplacement(Matcher.java:857)
	at scala.util.matching.Regex$Replacement$class.replace(Regex.scala:804)
	at scala.util.matching.Regex$MatchIterator$$anon$1.replace(Regex.scala:782)
	at scala.util.matching.Regex$$anonfun$replaceAllIn$1.apply(Regex.scala:473)
	at scala.util.matching.Regex$$anonfun$replaceAllIn$1.apply(Regex.scala:473)
	at scala.collection.Iterator$class.foreach(Iterator.scala:893)
	at scala.collection.AbstractIterator.foreach(Iterator.scala:1336)
	at scala.util.matching.Regex.replaceAllIn(Regex.scala:473)
	at org.neo4j.cypher.internal.compiler.v3_1.planDescription.PlanDescriptionArgumentSerializer$.removeGeneratedNames(PlanDescriptionArgumentSerializer.scala:91)
	at org.neo4j.cypher.internal.compiler.v3_1.planDescription.PlanDescriptionArgumentSerializer$.serialize(PlanDescriptionArgumentSerializer.scala:36)
	at org.neo4j.cypher.internal.compatibility.CompatibilityPlanDescriptionFor3_1$$anonfun$arguments$1$$anonfun$apply$3.apply(CompatibilityFor3_1.scala:436)
	at org.neo4j.cypher.internal.compatibility.CompatibilityPlanDescriptionFor3_1$$anonfun$arguments$1$$anonfun$apply$3.apply(CompatibilityFor3_1.scala:436)
	at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
	at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
	at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
	at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
	at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
	at scala.collection.AbstractTraversable.map(Traversable.scala:104)
	at org.neo4j.cypher.internal.compatibility.CompatibilityPlanDescriptionFor3_1$$anonfun$arguments$1.apply(CompatibilityFor3_1.scala:436)
	at org.neo4j.cypher.internal.compatibility.CompatibilityPlanDescriptionFor3_1$$anonfun$arguments$1.apply(CompatibilityFor3_1.scala:436)
	at org.neo4j.cypher.internal.compatibility.exceptionHandlerFor3_1$runSafely$.apply(CompatibilityFor3_1.scala:192)
	at org.neo4j.cypher.internal.compatibility.CompatibilityPlanDescriptionFor3_1.arguments(CompatibilityFor3_1.scala:435)
	at org.neo4j.cypher.internal.javacompat.Description.getArguments(Description.java:72)
	at org.neo4j.bolt.v1.runtime.cypher.ExecutionPlanConverter.convert(ExecutionPlanConverter.java:36)
	at org.neo4j.bolt.v1.runtime.cypher.ExecutionPlanConverter.children(ExecutionPlanConverter.java:53)
	at org.neo4j.bolt.v1.runtime.cypher.ExecutionPlanConverter.convert(ExecutionPlanConverter.java:38)
	at org.neo4j.bolt.v1.runtime.cypher.ExecutionPlanConverter.children(ExecutionPlanConverter.java:53)
	at org.neo4j.bolt.v1.runtime.cypher.ExecutionPlanConverter.convert(ExecutionPlanConverter.java:38)
	at org.neo4j.bolt.v1.runtime.cypher.ExecutionPlanConverter.children(ExecutionPlanConverter.java:53)
	at org.neo4j.bolt.v1.runtime.cypher.ExecutionPlanConverter.convert(ExecutionPlanConverter.java:38)
	at org.neo4j.bolt.v1.runtime.cypher.CypherAdapterStream.accept(CypherAdapterStream.java:86)
	at org.neo4j.bolt.v1.messaging.BoltMessageRouter$ResultHandler.onRecords(BoltMessageRouter.java:130)
	at org.neo4j.bolt.v1.runtime.BoltStateMachine$State$3.lambda$pullAll$0(BoltStateMachine.java:451)
	at org.neo4j.bolt.v1.runtime.TransactionStateMachine$State$2.streamResult(TransactionStateMachine.java:274)
	at org.neo4j.bolt.v1.runtime.TransactionStateMachine.streamResult(TransactionStateMachine.java:93)
	at org.neo4j.bolt.v1.runtime.BoltStateMachine$State$3.pullAll(BoltStateMachine.java:450)
	at org.neo4j.bolt.v1.runtime.BoltStateMachine.pullAll(BoltStateMachine.java:233)
	at org.neo4j.bolt.v1.messaging.BoltMessageRouter.lambda$onPullAll$6(BoltMessageRouter.java:98)
	at org.neo4j.bolt.v1.runtime.concurrent.RunnableBoltWorker.execute(RunnableBoltWorker.java:135)
	at org.neo4j.bolt.v1.runtime.concurrent.RunnableBoltWorker.executeBatch(RunnableBoltWorker.java:122)
	at org.neo4j.bolt.v1.runtime.concurrent.RunnableBoltWorker.run(RunnableBoltWorker.java:94)
	at java.lang.Thread.run(Thread.java:748)

Filter explanation:

  • If the node.values contains a text that starts with 'T' followed by numbers, use the first occurrence of this value and remove the letter 'T'. Otherwise use a literal value.
  • Compare result from case statement with the given parameter value.

I know that the statement can be written in a completely different way avoiding the exception (that is not the point). This is a simplification of a very large statement, using only the expression that triggers the exception. Commenting the problematic statement and enabling one of the other two versions will execute without problems returning the correct results.

It is the combination of the expression + PROFILE + parameter the one that triggers the error. It cannot be replicated on the Browser console since it does not support parameters.

Async/Future based .run()

I know this is still a WIP,

but are you planning on adding an async version of .run() which returns a Future?

Tests are failing

mvn clean install

....
java.io.FileNotFoundException: /Users/mh/java/neo/java-driver/driver/../neo4j-driver-test-server-2.3-SNAPSHOT.jar (No such file or directory)

Intermittent SSL socket connection failure

Neo4j Java driver version: 1.0.4
Neo4j server version: 3.0.3

We are using a 3-node HA cluster setup in AWS with 2 ELBs; one for read operations pointing to the slave nodes, and one for write operations pointing to the master node. The ELBs are configured to use the Neo4j management end-points for health checks and to fail over when one of the nodes goes down and the 'master' moves. The ELBs are also configured to pass SSL traffic to the back-end servers, so SSL termination is done on the Neo4j server instances.  Our application code has Neo4j Driver object instances for read and write operations that connect to the corresponding ELB instance using the BOLT protocol and requiring encryption.  

The problem we are having is periodic failure by the Neo4j Driver to establish an SSL connection.  It seems that after some period of inactivity, a request to read something from the graph results in a failure to establish an SSL connection.  Issuing the same request again succeeds.

Here is the relevant stack trace:

org.neo4j.driver.v1.exceptions.ClientException:
Failed to establish SSL socket connection. at org.neo4j.driver.internal.connector.socket.TLSSocketChannel.unwrap(TLSSocketChannel.java:179) at org.neo4j.driver.internal.connector.socket.TLSSocketChannel.read(TLSSocketChannel.java:374) at org.neo4j.driver.internal.connector.socket.BufferingChunkedInput.readNextPacket(BufferingChunkedInput.java:408)
at org.neo4j.driver.internal.connector.socket.BufferingChunkedInput.readChunkSize(BufferingChunkedInput.java:344) at org.neo4j.driver.internal.connector.socket.BufferingChunkedInput.read(BufferingChunkedInput.java:246) at org.neo4j.driver.internal.connector.socket.BufferingChunkedInput.fillScratchBuffer(BufferingChunkedInput.java:215)
at org.neo4j.driver.internal.connector.socket.BufferingChunkedInput.readByte(BufferingChunkedInput.java:109) at org.neo4j.driver.internal.packstream.PackStream$Unpacker.unpackStructHeader(PackStream.java:441) at org.neo4j.driver.internal.messaging.PackStreamMessageFormatV1$Reader.read(PackStreamMessageFormatV1.java:397)
at org.neo4j.driver.internal.connector.socket.SocketClient.receiveOne(SocketClient.java:130) at org.neo4j.driver.internal.connector.socket.SocketClient.receiveAll(SocketClient.java:124) at org.neo4j.driver.internal.connector.socket.SocketConnection.receiveAll(SocketConnection.java:121)
at org.neo4j.driver.internal.connector.socket.SocketConnection.sync(SocketConnection.java:100) at org.neo4j.driver.internal.connector.ConcurrencyGuardingConnection.sync(ConcurrencyGuardingConnection.java:122) at org.neo4j.driver.internal.pool.PooledConnection.sync(PooledConnection.java:144)
at org.neo4j.driver.internal.InternalSession.close(InternalSession.java:130)

Here are relevant code snippets:

Driver neo4jReadDriver = GraphDatabase.driver(serverURI,
            AuthTokens.basic(username, password),
            Config.build()
                    .withEncryptionLevel(Config.EncryptionLevel.REQUIRED)
                    .toConfig());

private StatementResult run(Driver neo4jDriver, String statementTemplate, Map<String, Object> statementParameters) {
    try (Session neo4jSession = neo4jDriver.session()) {
        return neo4jSession.run(statementTemplate, statementParameters);
    }
}

String cypherStatement = "<cypher>";
HashMap<String, Object> params = new HashMap<>();
StatementResult result = run(neo4jReadDriver, cypherStatement, params);

The SSL connection failure happens at the end of the 'try' block when the session is closed. An immediate re-try of the same call succeeds.

Are there any recommended configuration settings for using the Neo4j driver with AWS ELBs?
Have the Neo4j drivers been tested in HA configurations using AWS and ELBs? Are there any recommended configuration settings when deploying into AWS and using ELBs?

Issue with Clojure Map Interop

A Clojure map both implements the interfaces - java.util.Map and java.lang.Iterable.

Currently while encoding the data, the latter interface is used and not the former. See Value.value method.

It would be better to use the former. So if value is a instance of Map should be moved up in the method.

Thank you.

(Bolt) Use of ServiceUnavailableException in TLS-enabled channel

Hi,

I'm trying to debug a potential issue in neo4j-ogm that might be related to Bolt session handling after a server restart (see also: spring-projects/spring-data-neo4j#373). Before going any further, I have a doubt concerning the Java Driver:

  • For plaintext connections, the first operation after the restart results in a ServiceUnavailableException with the following message:

    "Connection terminated while receiving data. This can happen due to network instabilities, or due to restarts of the database."

  • For TLS-enabled connections, the first operation after the restart results in a ClientException with exactly the same message.

My question is, why are there two different exceptions instead of just using ServiceUnavailableException for both?


Just FYI, neo4j-ogm doesn't handle ServiceUnavailableException yet. It just wraps ClientExceptions coming from server disconnections or network glitches in CypherException, so the library user has to catch them and reconnect manually, invoking a new query.

session.close() hangs

Hi,

After loading around 600,000 nodes with relations in a Groovy script, the call of session.close() hangs and the scripts never exists.

My query is:

def entrepriseQuery = "match (e:Etablissement {siret: {siret}}) " +
        "merge (n:Entreprise {siren: {siren}}) " +
        "with e, n " +
        "merge (e)<-[:EST_SIEGE]-(n)"

I use in my project this library org.neo4j.driver:neo4j-java-driver:1.1.0-M06

Thanks

Error with session object leaking

Hello,

We are getting the error app="customer360-identity-qa2" log_level="ERROR" thread="Finalizer" Neo4j Session object leaked, please ensure that your application calls the close method on Sessions before disposing of the objects.

This seems to happen in proximity to whenever the database goes offline then back online, and we have every single session closed in the finally portion of a try catch block. We are using AKKA reactive streams to get information to the save function and also using the bolt protocol with neo4j.

Thanks

Getting a time out exception and cannot connect to my server anymore

Hi guys, I'm getting this exception:

2016-10-27 03:00:11,082 [brinqa-scheduler_Worker-2]     ERROR   ExceptionPrinterJobListener:213 Exception occurred in job: Grails Job
org.quartz.JobExecutionException: org.neo4j.driver.v1.exceptions.ClientException: Unable to send messages to server: Connection timed out [See nested exception: org.neo4j.driver.v1.exceptions.ClientException: Unable to send messages to server: Connection timed out]
        at grails.plugins.quartz.GrailsJobFactory$GrailsJob.execute(GrailsJobFactory.java:111)
        at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
        at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)

I'm running my application on a different box than my Neo4j server.
After this happens I cannot connect to the Neo4j server anymore until I restart my application. It looks like the connection gets lost for some reason and it cannot be reestablished.
This happens many times a day.

Exception when using neo4j-java-driver as part of hibernate-ogm

Some weeks ago hibernate-ogm has been released in version 5.1.0.Alpha1. The release added support for connecting to neo4j servers via bolt by making use of neo4j-java-driver.

I tried to use this new feature but ran into a problem which seems to be caused by the driver (but I'm not 100% sure about this).

Starting my glassfish I get the following exception:

java.util.ServiceConfigurationError: org.neo4j.driver.internal.spi.Connector: Provider org.neo4j.driver.internal.connector.socket.SocketConnector not a subtype
    at java.util.ServiceLoader.fail(ServiceLoader.java:239)
    at java.util.ServiceLoader.access$300(ServiceLoader.java:185)
    at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:376)
    at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:404)
    at java.util.ServiceLoader$1.next(ServiceLoader.java:480)
    at org.neo4j.driver.internal.pool.InternalConnectionPool.loadConnectors(InternalConnectionPool.java:145)
    at org.neo4j.driver.internal.pool.InternalConnectionPool.<init>(InternalConnectionPool.java:77)
    at org.neo4j.driver.internal.InternalDriver.<init>(InternalDriver.java:41)
    at org.neo4j.driver.v1.GraphDatabase.driver(GraphDatabase.java:128)
    at org.neo4j.driver.v1.GraphDatabase.driver(GraphDatabase.java:112)
    at org.neo4j.driver.v1.GraphDatabase.driver(GraphDatabase.java:87)
    at org.hibernate.ogm.datastore.neo4j.remote.bolt.impl.BoltNeo4jClient.createNeo4jDriver(BoltNeo4jClient.java:39)
    at org.hibernate.ogm.datastore.neo4j.remote.bolt.impl.BoltNeo4jClient.<init>(BoltNeo4jClient.java:32)
    at org.hibernate.ogm.datastore.neo4j.remote.bolt.impl.BoltNeo4jDatastoreProvider.start(BoltNeo4jDatastoreProvider.java:57)

I am suprised about this message since SocketConnector is a subtype of Connector and the service seems to be correctly configured under META-INF.services.

The code which causes the failure is located in the java.util.ServiceLoader:375:

if (!service.isAssignableFrom(c)) {
    fail(service, "Provider " + cn  + " not a subtype");
}

Is this a bug in the driver, might it be a configuration error in my project or is it likely a problem in hibernate-ogm? The framework uses version 1.0.4. of neo4j-java-driver.

Update: I have seen that the service definition has been refactored with release 1.1.0-M6. Using this version the exception no longer appears. Nevertheless I am interessed what's the problem with version 1.1.0-M5 and beyond.

Update 2: An example to reproduce this issue can be found in my repository: https://github.com/Restage/HibernateOgmExample
Just run a Neo4j instance with the parameters given in the persistence.xml. If you than start the ear on a glassfish4 the exception should be shown.

M05: Closing a StatementResult

If I open a transaction to execute multiple statements, is there a way to just close a StatementResult if I need to without having to close the entire session or transaction?
There's a consume() but that will consume the entire result- is that the recommended way to close?

TLSSocketChannel BufferOverflow

Hi guys,

I'm getting the following error after running a process for 40-60 min that writes 5-8 nodes per second.

Failed to enlarge network buffer from 16921 to 16921. This is either because the new size is however less than the old size, or because the application buffer size 8192 is so big that the application data still cannot fit into the new network buffer.

Neo4j: 3.0.0 Enterprise Trial
Driver: 1.0.0
Language: Scala 2.11.8
OS: Centos 7

And adding to that, I found a "TODO" comment in the OFFICIAL driver where this error is being traced.

 case BUFFER_OVERFLOW:
            // Enlarge the buffer and return the old status
            int curNetSize = cipherOut.capacity();
            int netSize = sslEngine.getSession().getPacketBufferSize();
            if ( curNetSize >= netSize || buffer.capacity() > netSize )
            {
                // TODO
                throw new ClientException(
                        String.format( "Failed to enlarge network buffer from %s to %s. This is either because the " +
                                       "new size is however less than the old size, or because the application " +
                                       "buffer size %s is so big that the application data still cannot fit into the " +
                                       "new network buffer.", curNetSize, netSize, buffer.capacity() ) );
            }

Constraint violated exceptions result in some other bolt transactions hanging

This is a bit difficult to describe, and not sure whether I can write a clean test for it, but here's what is happening. I have a couple of test suites that hang on some tests only if one of the previous tests executed Cypher statements that resulted in a Constraint violation exception.
When stepping through the hanging test, tx.run returns, but then, StatementResult.keys() hangs, specifically in ConcurrencyGuardingConnection.receiveOne() -> delegate.receiveOne()
Using version 1.1.1

Result::fieldNames is empty after query execution

We create 3 nodes in database:

CREATE (m:Movie {title: 'Lord of the Rings', author: 'J. R. R. Tolkien'})
CREATE (a:Actor {name: 'Orlando Bloom'})
CREATE (m:Movie {title: 'Troy', author: 'Homer'})

Then we try to execute select query:

MATCH (n) RETURN n

Expected: 3 nodes returned, under n key
What we have: result contains 3 nodes, but fieldsNames property is empty.

Debug result:

// driver/src/main/java/org/neo4j/driver/internal/StandardTransaction.java:121
conn.sync(); // <<<< 1
return resultBuilder.build(); // <<<< 2
Sync phase (1)

ResultBuilder - stateful container. Field names are populated in fieldNames method.
This method is called when success message received:

// /driver/src/main/java/org/neo4j/driver/internal/messaging/PackStreamMessageFormatV1.java:368
case MSG_SUCCESS:
    unpackSuccessMessage( handler );
    break;

When we execute query we have this handling order:

  • success (fieldNames populated)
  • record (body populated)
  • record (body populated)
  • record (body populated)
  • success (fieldNames populated)

So, on first success we correctly receive fieldNames:

fieldLookup.toString()
// {n=0}

But, when second success is received we call fieldNames() on ResultBuilder with no names.
So, second success message doesn't containt any names.
And this message overrides fieldNames from first success message.

Build phase (2)

Now in builder state we have valid body with 3 records. But fieldNames is empty.


I am not sure where I should look to fix this problem. If you can point me to correct place in the code, I can try to fix this problem and open pull request.

Unexpected "Relationship has been deleted in this transaction"

When I create two nodes and a relationship (each one with a separate statement) in an empty database, and delete the relationship in the same transaction, I get an unexpected "Relationship with id 0 has been deleted in this transaction" exception when commiting the transaction.

I was not able to reproduce the error using only the neo4j-java-driver, so the problem seems to exist somewhere in the way our wrapping code executes the individual statements.

I was hoping that you can shed some light on what happens in the database if I provide the unencrypted tcpdump of the transaction:

bolt-transaction.txt

Please feel free to close the issue if this is the wrong place for this kind of question!

Thanks and best regards,
Christian

NullPointerException at org.neo4j.driver.internal.InternalSession$2.run when an invalid Cypher query is executed

With 1.0.0-M05, this exception is thrown

Exception in thread "main" java.lang.NullPointerException
    at org.neo4j.driver.internal.InternalSession$2.run(InternalSession.java:140)
    at org.neo4j.driver.internal.pool.PooledConnection.onDelegateException(PooledConnection.java:197)
    at org.neo4j.driver.internal.pool.PooledConnection.receiveOne(PooledConnection.java:146)
    at org.neo4j.driver.internal.InternalStatementResult.tryFetching(InternalStatementResult.java:344)
    at org.neo4j.driver.internal.InternalStatementResult.hasNext(InternalStatementResult.java:190)

when you attempt to execute an invalid Cypher query using session.run. This only happens when a previous transaction has been carried out in the same session.

Session session = driver.session();

//Must have a transaction first
Transaction tx = session.beginTransaction();
StatementResult result = tx.run("CREATE (n) RETURN n");
if (result.hasNext()) {
    result.next();
}
result.consume();
tx.success();
tx.close();

//Now the bad query
StatementResult badResult = session.run("CREAT (n) RETURN n");
if (badResult.hasNext()) {
    badResult.next();
}

Without the previous tx, badResult is executed and produces
Exception in thread "main" org.neo4j.driver.v1.exceptions.ClientException: Invalid input ' ': expected 'e/E' (line 1, column 6 (offset: 5)) as expected.

If badResult was a valid query badResult = session.run("CREATE (n) RETURN n"); then both execute fine.

Proper database version to use with current driver?

Hi,

Currently I am trying to integrate driver in our solution.
We use neo4j-harness for integration test layer. I enabled NDP there. Looks like that everything is up-and-running, but I face some strange errors during query execution (it receive non-expected response from server).

Am I right that I should build from source, from latest(master) version of Neo4j to experiment with NDP?

Concurrent MERGE creates duplicate relationships in separate threads/Sessions

Expected result

The following query should create exactly one relationship between the two nodes, even if executed concurrently by multiple threads:

MATCH (n), (m) WHERE ID(n) = {id1} AND ID(m) = {id2}
MERGE (n)-[r:TEST]->(m)

Actual result

When using muitple threads with their own Session, the result of the above query is not unique, creating n relationships for n threads. See also the example code below which creates the following output:

Simple merge with a single session:  1
Simple merge with multiple sessions: 3
Locked merge with a single session:  1
Locked merge with multiple sessions: 1

Workaround

As illustrated by the example code below, locking can be enforced with a simple trick from the Neo4j documentation. The below Cypher statement creates exactly one relationship even with multiple sessions in separate threads.

MATCH (n), (m) WHERE ID(n) = {id1} AND ID(m) = {id2}
SET n.locked = true, m.locked = true
MERGE (n)-[r:TEST]->(m)
SET n.locked = Null, m.locked = Null

Status

This issue is not critical for us because there is a workaround which we can use. I'm not sure if the issue even qualifies as a bug, so please close if it doesn't!

Example code

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package org.structr.test;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.neo4j.driver.v1.AuthTokens;
import org.neo4j.driver.v1.Config;
import org.neo4j.driver.v1.Driver;
import org.neo4j.driver.v1.GraphDatabase;
import org.neo4j.driver.v1.Session;
import org.neo4j.driver.v1.StatementResult;
import org.neo4j.driver.v1.Transaction;
import org.neo4j.driver.v1.types.Node;
import org.neo4j.driver.v1.types.Relationship;

/**
 *
 * @author Christian Morgner
 */
public class Duplicate {

    public static void main(final String[] args) {

        System.out.println("Simple merge with a single session:  " + testSimpleMergeWithASingleSession());
        System.out.println("Simple merge with multiple sessions: " + testSimpleMergeWithMultipleSessions());
        System.out.println("Locked merge with a single session:  " + testLockedMergeWithASingleSession());
        System.out.println("Locked merge with multiple sessions: " + testLockedMergeWithMultipleSessions());
    }

    public static int testSimpleMergeWithASingleSession() {

        try (final Driver driver = GraphDatabase.driver("bolt://localhost:7687",
                        AuthTokens.basic("neo4j", "test"),
                        Config.build().withEncryptionLevel(Config.EncryptionLevel.NONE).toConfig()
            )) {

            final Node startNode;
            final Node endNode;

            try (final Session session = driver.session()) {

                // create two nodes
                try (final Transaction tx = session.beginTransaction()) {

                    tx.run("MATCH (n)-[r:TEST]->(m) DELETE n, r, m");

                    startNode          = getNodeFromStatement(tx, "CREATE (n) RETURN n", Collections.EMPTY_MAP);
                    endNode            = getNodeFromStatement(tx, "CREATE (n) RETURN n", Collections.EMPTY_MAP);

                    tx.success();
                }

                // relationship creation runner
                final Runnable runner = () -> {

                    try (final Transaction tx = session.beginTransaction()) {

                        final Map<String, Object> map = new HashMap<>();

                        map.put("id1", startNode.id());
                        map.put("id2", endNode.id());

                        tx.run("MATCH (n), (m) WHERE ID(n) = {id1} AND ID(m) = {id2} MERGE (n)-[r:TEST]->(m) RETURN r", map);

                        tx.success();
                    }
                };

                // start relationship creation two times
                final ExecutorService service = Executors.newCachedThreadPool();
                final Future f1               = service.submit(runner);
                final Future f2               = service.submit(runner);
                final Future f3               = service.submit(runner);

                try {
                    f1.get();
                    f2.get();
                    f3.get();

                } catch (Throwable ignore) {}

                service.shutdown();

                // create two nodes
                try (final Transaction tx = session.beginTransaction()) {

                    // verify that there is only a single relationship
                    final StatementResult result = tx.run("MATCH (n)-[r:TEST]->(m) RETURN count(r)");
                    if (result.hasNext()) {

                        return result.single().get("count(r)").asNumber().intValue();
                    }

                    tx.success();
                }
            }
        }

        return -1;
    }

    public static int testSimpleMergeWithMultipleSessions() {

        try (final Driver driver = GraphDatabase.driver("bolt://localhost:7687",
                        AuthTokens.basic("neo4j", "test"),
                        Config.build().withEncryptionLevel(Config.EncryptionLevel.NONE).toConfig()
            )) {

            final Node startNode;
            final Node endNode;

            try (final Session session = driver.session()) {

                // create two nodes
                try (final Transaction tx = session.beginTransaction()) {

                    tx.run("MATCH (n)-[r:TEST]->(m) DELETE n, r, m");

                    startNode          = getNodeFromStatement(tx, "CREATE (n) RETURN n", Collections.EMPTY_MAP);
                    endNode            = getNodeFromStatement(tx, "CREATE (n) RETURN n", Collections.EMPTY_MAP);

                    tx.success();
                }
            }

            // relationship creation runner
            final Runnable runner = () -> {

                try (final Session session = driver.session()) {
                    try (final Transaction tx = session.beginTransaction()) {

                        final Map<String, Object> map = new HashMap<>();

                        map.put("id1", startNode.id());
                        map.put("id2", endNode.id());

                        tx.run("MATCH (n), (m) WHERE ID(n) = {id1} AND ID(m) = {id2} MERGE (n)-[r:TEST]->(m) RETURN r", map);
                        //tx.run("MATCH (n), (m) WHERE ID(n) = {id1} AND ID(m) = {id2} SET n.l = true, m.l = true MERGE (n)-[r:TEST]->(m) set n.l = Null, m.l = Null RETURN r", map);

                        tx.success();
                    }
                }
            };

            // start relationship creation two times
            final ExecutorService service = Executors.newCachedThreadPool();
            final Future f1               = service.submit(runner);
            final Future f2               = service.submit(runner);
            final Future f3               = service.submit(runner);

            try {
                f1.get();
                f2.get();
                f3.get();

            } catch (Throwable ignore) {}

            service.shutdown();

            try (final Session session = driver.session()) {


                // create two nodes
                try (final Transaction tx = session.beginTransaction()) {

                    // verify that there is only a single relationship
                    final StatementResult result = tx.run("MATCH (n)-[r:TEST]->(m) RETURN count(r)");
                    if (result.hasNext()) {

                        return result.single().get("count(r)").asNumber().intValue();
                    }

                    tx.success();
                }
            }
        }

        return -1;
    }

    public static int testLockedMergeWithASingleSession() {

        try (final Driver driver = GraphDatabase.driver("bolt://localhost:7687",
                        AuthTokens.basic("neo4j", "test"),
                        Config.build().withEncryptionLevel(Config.EncryptionLevel.NONE).toConfig()
            )) {

            final Node startNode;
            final Node endNode;

            try (final Session session = driver.session()) {

                // create two nodes
                try (final Transaction tx = session.beginTransaction()) {

                    tx.run("MATCH (n)-[r:TEST]->(m) DELETE n, r, m");

                    startNode          = getNodeFromStatement(tx, "CREATE (n) RETURN n", Collections.EMPTY_MAP);
                    endNode            = getNodeFromStatement(tx, "CREATE (n) RETURN n", Collections.EMPTY_MAP);

                    tx.success();
                }

                // relationship creation runner
                final Runnable runner = () -> {

                    try (final Transaction tx = session.beginTransaction()) {

                        final Map<String, Object> map = new HashMap<>();

                        map.put("id1", startNode.id());
                        map.put("id2", endNode.id());

                        tx.run("MATCH (n), (m) WHERE ID(n) = {id1} AND ID(m) = {id2} SET n.l = true, m.l = true MERGE (n)-[r:TEST]->(m) set n.l = Null, m.l = Null RETURN r", map);
                        tx.success();
                    }
                };

                // start relationship creation two times
                final ExecutorService service = Executors.newCachedThreadPool();
                final Future f1               = service.submit(runner);
                final Future f2               = service.submit(runner);
                final Future f3               = service.submit(runner);

                try {
                    f1.get();
                    f2.get();
                    f3.get();

                } catch (Throwable ignore) {}

                service.shutdown();

                // create two nodes
                try (final Transaction tx = session.beginTransaction()) {

                    // verify that there is only a single relationship
                    final StatementResult result = tx.run("MATCH (n)-[r:TEST]->(m) RETURN count(r)");
                    if (result.hasNext()) {

                        return result.single().get("count(r)").asNumber().intValue();
                    }

                    tx.success();
                }
            }
        }

        return -1;
    }

    public static int testLockedMergeWithMultipleSessions() {

        try (final Driver driver = GraphDatabase.driver("bolt://localhost:7687",
                        AuthTokens.basic("neo4j", "test"),
                        Config.build().withEncryptionLevel(Config.EncryptionLevel.NONE).toConfig()
            )) {

            final Node startNode;
            final Node endNode;

            try (final Session session = driver.session()) {

                // create two nodes
                try (final Transaction tx = session.beginTransaction()) {

                    tx.run("MATCH (n)-[r:TEST]->(m) DELETE n, r, m");

                    startNode          = getNodeFromStatement(tx, "CREATE (n) RETURN n", Collections.EMPTY_MAP);
                    endNode            = getNodeFromStatement(tx, "CREATE (n) RETURN n", Collections.EMPTY_MAP);

                    tx.success();
                }
            }

            // relationship creation runner
            final Runnable runner = () -> {

                try (final Session session = driver.session()) {

                    try (final Transaction tx = session.beginTransaction()) {

                        final Map<String, Object> map = new HashMap<>();

                        map.put("id1", startNode.id());
                        map.put("id2", endNode.id());

                        tx.run("MATCH (n), (m) WHERE ID(n) = {id1} AND ID(m) = {id2} SET n.l = true, m.l = true MERGE (n)-[r:TEST]->(m) set n.l = Null, m.l = Null RETURN r", map);
                        tx.success();
                    }
                }
            };

            // start relationship creation two times
            final ExecutorService service = Executors.newCachedThreadPool();
            final Future f1               = service.submit(runner);
            final Future f2               = service.submit(runner);
            final Future f3               = service.submit(runner);

            try {
                f1.get();
                f2.get();
                f3.get();

            } catch (Throwable ignore) {}

            service.shutdown();

            try (final Session session = driver.session()) {


                // create two nodes
                try (final Transaction tx = session.beginTransaction()) {

                    // verify that there is only a single relationship
                    final StatementResult result = tx.run("MATCH (n)-[r:TEST]->(m) RETURN count(r)");
                    if (result.hasNext()) {

                        return result.single().get("count(r)").asNumber().intValue();
                    }

                    tx.success();
                }
            }
        }

        return -1;
    }

    private static Node getNodeFromStatement(final Transaction tx, final String statement, final Map<String, Object> map) {
        return tx.run(statement, map).single().get(0).asNode();
    }

    private static Relationship getRelationshipFromStatement(final Transaction tx, final String statement, final Map<String, Object> map) {
        return tx.run(statement, map).single().get(0).asRelationship();
    }
}

question about InternalSession.isOpen method

Hi All, I'm Lorenzo from the Neo4j JDBC driver team.

I'm contacting you because we have this open issue 69 that looks like to be somehow related to your InternalSession.isOpen method.
In fact, the guy that opened this issue is also proposing to slightly change this your method to solve his problem (please see: issue 69 comment).

Design choice for the JDBC Driver's BOLT implementation was to wrap as much as possible this your java driver (carefully monitoring the overhead we're introducing not to lower performances): that's why we'd like to keep calling your methods instead of rewriting the same logic of you.

So, what's your opinion about this our issue? Do you think this is something we'd solve from our side or the proposed patch sounds reasonable for you? Or whatelse?

Cheers,
Lorenzo

General SSLEngine problem

I am running a Java Neo4j driver and have this :

Driver driver = GraphDatabase.driver("bolt://localhost", AuthTokens.basic( "neo4j", "password" ) );
Session session = driver.session();
when executing the last line, it will throw an error:

"General SSLEngine problem"
It worked for Neo4j 3.0.0 but after upgrading to 3.0.1

Underscores in URI cause NullPointerExceptions

I'm running a Neo4j application with the Bolt driver on GitLab's CI, where attached Docker services are referenced with hostnames including underscores (specifically double underscores to replace forward slashes in the Docker image name). This causes the Bolt driver to throw NullPointerExceptions:

   org.neo4j.ogm.exception.ConnectionException: Error connecting to graph database using Bolt
        at org.neo4j.ogm.drivers.bolt.driver.BoltDriver.newSession(BoltDriver.java:101)
        at org.neo4j.ogm.drivers.bolt.driver.BoltDriver.newTransaction(BoltDriver.java:73)
        at org.neo4j.ogm.session.transaction.DefaultTransactionManager.openTransaction(DefaultTransactionManager.java:71)
        at org.neo4j.ogm.session.transaction.DefaultTransactionManager.openTransaction(DefaultTransactionManager.java:57)
        at org.neo4j.ogm.drivers.bolt.request.BoltRequest.executeRequest(BoltRequest.java:153)
        at org.neo4j.ogm.drivers.bolt.request.BoltRequest.execute(BoltRequest.java:81)
        at org.neo4j.ogm.session.delegates.DeleteDelegate.purgeDatabase(DeleteDelegate.java:265)
        at org.neo4j.ogm.session.Neo4jSession.purgeDatabase(Neo4jSession.java:417)
        at uk.ac.cam.cl.part1b1617.kilo.graph.GraphIntegrationTestBase.setUp(GraphIntegrationTestBase.java:14)
        at uk.ac.cam.cl.part1b1617.kilo.graph.JobManagerServiceImplIntegrationTest.setUp(JobManagerServiceImplIntegrationTest.java:19)

        Caused by:
        java.lang.NullPointerException
            at org.neo4j.driver.internal.net.BoltServerAddress.hashCode(BoltServerAddress.java:91)
            at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936)
            at org.neo4j.driver.internal.net.pooling.SocketConnectionPool.pool(SocketConnectionPool.java:129)
            at org.neo4j.driver.internal.net.pooling.SocketConnectionPool.acquire(SocketConnectionPool.java:109)
            at org.neo4j.driver.internal.DirectDriver.newSessionWithMode(DirectDriver.java:49)
            at org.neo4j.driver.internal.BaseDriver.session(BaseDriver.java:62)
            at org.neo4j.ogm.drivers.bolt.driver.BoltDriver.newSession(BoltDriver.java:97)
            ... 9 more

Verified locally with a hostname a_b which fails, and a-b which succeeds (well, failed with an unresolved host, but that's expected). Full URI would be bolt://a_b:7687

Threads don't terminate

While trying to solve this issue on the neo4j-jdbc-driver, I noticed that if I turn TLS encryption off this test doesn't terminate:

@Test
public void issue94OnlyJavaBoltDriver() {
  for (int i = 0; i < 2000; i++) {		
    Config.ConfigBuilder builder = build();
    builder = builder.withEncryptionLevel(Config.EncryptionLevel.NONE);
    Config config = builder.toConfig();
    Driver driver = GraphDatabase.driver( "bolt://localhost", AuthTokens.basic( "neo4j", "larus" ), config );
    try (Session s = driver.session()) {
      System.out.println(i);
    }
    catch (Exception e) {
      Assert.fail(e.getMessage());
    }
    driver.close();
  }
  System.out.println("done.");
}	

but as soon as I comment builder.withEncryptionLevel(Config.EncryptionLevel.NONE); then the test terminates successfully.

Yes, I shouldn't create a new driver instance per iteration, but on the other side I'm also closing it, so I'd expect the cycle not to result in any resource leak.

The problem is that threads remain opened.

Thanks for your kind reply.

Version 1.0.2 of Java driver not thread safe

Unless I am missing something the driver doesn't appear to be thread safe, which makes it unusable for most production scenarios. When accessed via multiple threads frequent exceptions occur:

org.neo4j.driver.v1.exceptions.ClientException: You are using a session from multiple locations at the same time, which is not supported. If you want to use multiple threads, you should ensure that each session is used by only one thread at a time. One way to do that is to give each thread its own dedicated session.

    at org.neo4j.driver.internal.connector.ConcurrencyGuardingConnection.markAsInUse(ConcurrencyGuardingConnection.java:192)
    at org.neo4j.driver.internal.connector.ConcurrencyGuardingConnection.run(ConcurrencyGuardingConnection.java:65)
    at org.neo4j.driver.internal.pool.PooledConnection.run(PooledConnection.java:64)
    at 

Initially I thought this was a bug in our object mapping implementation, but I wrote a test that uses the raw driver and the same issue occurs:

https://github.com/grails/grails-data-mapping/blob/master/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/MiscSpec.groovy#L156

String return in List adds extra "

Using the driver in a scala environment if I do this:

// create the object with a list of Strings inside
val javaResults = session.run("CREATE (t:Test {list: ['1']}) RETURN t").list()

// Convert to Scala list
val results = (for (i <- 0 until results.size) yield results.get(i)).toList

val list = results.head.get("t").get("list").asList(Values.ofToString).toList

Then the list is a list of Strings with extra " ie:

list.head == "1" // false
list.head == "\"1\"" // true -> extras "

In order to make it work I am using a workaround to remove leading and trailing character for each element of the list.

Opening concurrent sessions throws various exceptions

The following code

public class ConcurrentSessions {

    private static String query = "MATCH (n) return n";
    public static void main(String[] args) throws InterruptedException {
        Driver driver = GraphDatabase.driver( "bolt://localhost:7687", AuthTokens.basic( "neo4j", "neo" ),
                Config.build().withEncryptionLevel( Config.EncryptionLevel.NONE ).toConfig() );

        Set<Integer> sessions = new HashSet<>();
        ExecutorService executorService = Executors.newFixedThreadPool(1000);
        for (int i=0; i<1000;i++) {
            executorService.execute(() -> {
                try (Session session = driver.session()) {
                    try ( Transaction tx = session.beginTransaction() ) {
                        sessions.add(session.hashCode());
                        StatementResult result = tx.run( query);
                        result.consume();
                        tx.success();
                    }
                }
            });
        }
        executorService.shutdown();
        executorService.awaitTermination(5, TimeUnit.MINUTES);
        driver.close();
        System.out.println(sessions.size());
    }
}

throws either one of these two exceptions-

java.net.BindException: Address already in use
        at sun.nio.ch.Net.connect0(Native Method) ~[na:1.8.0_31]
        at sun.nio.ch.Net.connect(Net.java:457) ~[na:1.8.0_31]
        at sun.nio.ch.Net.connect(Net.java:449) ~[na:1.8.0_31]
        at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:647) ~[na:1.8.0_31]
        at org.neo4j.driver.internal.net.SocketClient$ChannelFactory.create(SocketClient.java:291) ~[neo4j-java-driver-1.1.0.jar:1.1.0-cec0652af796424e52867c859006da79b62d2ded]
        at org.neo4j.driver.internal.net.SocketClient.start(SocketClient.java:124) ~[neo4j-java-driver-1.1.0.jar:1.1.0-cec0652af796424e52867c859006da79b62d2ded]
SEVERE: ~~ [ERROR] You are using a session from multiple locations at the same time, which is not supported. If you want to use multiple threads, you should ensure that each session is used by only one thread at a time. One way to do that is to give each thread its own dedicated session.

Using version 1.1.0 and Neo4j 3.0.8

Missing getId() method for Node and Relationship values

We have compatibility layer - GraphDatabaseService implementation. We return nodes with their internal ID's.

Currently, as I see - there is no separate method to retrieve Node/Relationship internal id.

// driver/src/main/java/org/neo4j/driver/internal/messaging/PackStreamMessageFormatV1.java:499
String urn = unpacker.unpackString();

I suppose that, currently, id isn't transmitted to client as separate value.
String is returned and then used as identity. This string looks like node/0.

So, currently I use such code to extract id:

Node node = value.asNode();
Long.parseLong(node.identity().toString().split("/")[1]) ;

Question: is there possibility to acquire ID for node/relationship?

maven dependency failure

I want to make a simple connection to neo4j using the neo4j-java-driver.
i created a maven folder and added the dependency in the pom.xml:

This is my pom.xml file:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>my-app</name>
  <url>http://maven.apache.org</url>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>2.2</version>
        </plugin>
    </plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>org.neo4j.driver</groupId>
      <artifactId>neo4j-java-driver</artifactId>
      <version>1.0.6</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

and this is my java code:

package com.mycompany.app;
import org.neo4j.driver.v1.*;
class App 
{
    public static void main( String[] args )
    {
    	Driver driver = GraphDatabase.driver( "bolt://localhost:7687", AuthTokens.basic( "neo4j", "admin1234" ) );
		Session session = driver.session();

		session.run( "CREATE (a:Person {name:'Arthur', title:'King'})" );

		StatementResult result = session.run( "MATCH (a:Person) WHERE a.name = 'Arthur' RETURN a.name AS name, a.title AS title" );
        System.out.println( "Hello World hassan again!" );
    }
}

and this is the error after running it:
Exception in thread "main" java.lang.NoClassDefFoundError: org/neo4j/driver/v1/AuthTokens
at com.mycompany.app.App.main(App.java:13)
Caused by: java.lang.ClassNotFoundException: org.neo4j.driver.v1.AuthTokens
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 1 more

and this is the poutput for mvn depedency:tree

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building my-app 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.2:tree (default-cli) @ my-app ---
[INFO] com.mycompany.app:my-app:jar:1.0-SNAPSHOT
[INFO] +- org.neo4j.driver:neo4j-java-driver:jar:1.0.6:compile
[INFO] - junit:junit:jar:3.8.1:test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.257s
[INFO] Finished at: Fri Nov 18 04:26:24 EST 2016
[INFO] Final Memory: 7M/17M
[INFO] ------------------------------------------------------------------------

PackStream$Unexpected exception when trying to do performance benchmark

Hi,

I integrated NDP as transport layer in our Neo4j access layer. Also I created performance tests.
JMH is used as performance test runner.

Performance test explanation - before test execution we create X nodes. Inside test method we query all X nodes.

Code example:

// Driver is wrapped into our code
@Benchmark
public void getNodesNdp(World world, Blackhole bh) {
    try (Transaction tx = world.serverNdpDb().beginTx()) {
        Result nodes = world.serverNdpDb().execute(GET_NODES_QUERY);
        while (nodes.hasNext()) {
            Map<String, Object> next = nodes.next();
            bh.consume(next);
        }
        tx.success();
    }
}

X = 1

# JMH 1.9.3 (released 35 days ago)
# VM invoker: /usr/lib/jvm/java-7-oracle/jre/bin/java
# VM options: -Xmx1024m -Xms1024m -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:-OmitStackTraceInFastThrow -XX:hashCode=5 -DprepareNodeCount=1
# Warmup: 2 iterations, 30 s each
# Measurement: 3 iterations, 30 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: GetNodesBenchmark.getNodesNdp

# Run progress: 0.00% complete, ETA 00:02:30
# Fork: 1 of 1
# Warmup Iteration   1: 0.849 ms/op
# Warmup Iteration   2: 0.450 ms/op
Iteration   1: 0.475 ms/op
Iteration   2: 0.469 ms/op
Iteration   3: 0.536 ms/op


Result "getNodesNdp":
  0.493 ±(99.9%) 0.673 ms/op [Average]
  (min, avg, max) = (0.469, 0.493, 0.536), stdev = 0.037
  CI (99.9%): [≈ 0, 1.166] (assumes normal distribution)


# Run complete. Total time: 00:02:41

Benchmark                      Mode  Cnt  Score   Error  Units
GetNodesBenchmark.getNodesNdp  avgt    3  0.493 ± 0.673  ms/op

X = 100

# JMH 1.9.3 (released 35 days ago)
# VM invoker: /usr/lib/jvm/java-7-oracle/jre/bin/java
# VM options: -Xmx1024m -Xms1024m -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:-OmitStackTraceInFastThrow -XX:hashCode=5 -DprepareNodeCount=100
# Warmup: 2 iterations, 30 s each
# Measurement: 3 iterations, 30 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: GetNodesBenchmark.getNodesNdp

# Run progress: 0.00% complete, ETA 00:02:30
# Fork: 1 of 1
# Warmup Iteration   1: 4.197 ms/op
# Warmup Iteration   2: 2.193 ms/op
Iteration   1: 2.024 ms/op
Iteration   2: 1.778 ms/op
Iteration   3: 1.830 ms/op


Result "getNodesNdp":
  1.877 ±(99.9%) 2.367 ms/op [Average]
  (min, avg, max) = (1.778, 1.877, 2.024), stdev = 0.130
  CI (99.9%): [≈ 0, 4.244] (assumes normal distribution)


# Run complete. Total time: 00:02:47

Benchmark                      Mode  Cnt  Score   Error  Units
GetNodesBenchmark.getNodesNdp  avgt    3  1.877 ± 2.367  ms/op

X = 500

And here we got an exception.
Note: the only one thing that we changed is how many nodes we have in our database.

# JMH 1.9.3 (released 35 days ago)
# VM invoker: /usr/lib/jvm/java-7-oracle/jre/bin/java
# VM options: -Xmx1024m -Xms1024m -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:-OmitStackTraceInFastThrow -XX:hashCode=5 -DprepareNodeCount=500
# Warmup: 2 iterations, 30 s each
# Measurement: 3 iterations, 30 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: GetNodesBenchmark.getNodesNdp

# Run progress: 0.00% complete, ETA 00:02:30
# Fork: 1 of 1
# Warmup Iteration   1: 9.691 ms/op
# Warmup Iteration   2: 7.737 ms/op
Iteration   1: <failure>

org.neo4j.driver.exceptions.ClientException: Unable to read response from server: Expected a struct, but got: 2f
        at org.neo4j.driver.internal.connector.socket.SocketConnection.sync(SocketConnection.java:127)
        at org.neo4j.driver.internal.pool.PooledConnection.sync(PooledConnection.java:99)
        at org.neo4j.driver.internal.StandardTransaction.run(StandardTransaction.java:121)
        at com.neueda.neo4j.driver.client.communication.transport.ndp.executors.NdpCommandExecutor.executeInStream(NdpCommandExecutor.java:67)
        at com.neueda.neo4j.driver.client.ServerGraphDatabaseService.execute(ServerGraphDatabaseService.java:276)
        at com.neueda.neo4j.driver.client.ServerGraphDatabaseService.execute(ServerGraphDatabaseService.java:261)
        at com.neueda.neo4j.driver.tests.perf.bench.GetNodesBenchmark.getNodesNdp(GetNodesBenchmark.java:60)
        at com.neueda.neo4j.driver.tests.perf.bench.generated.GetNodesBenchmark_getNodesNdp.getNodesNdp_avgt_jmhStub(GetNodesBenchmark_getNodesNdp.java:213)
        at com.neueda.neo4j.driver.tests.perf.bench.generated.GetNodesBenchmark_getNodesNdp.getNodesNdp_AverageTime(GetNodesBenchmark_getNodesNdp.java:157)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:452)
        at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:434)
        at java.util.concurrent.FutureTask.run(FutureTask.java:262)
        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:745)
Caused by: org.neo4j.driver.internal.packstream.PackStream$Unexpected: Expected a struct, but got: 2f
        at org.neo4j.driver.internal.packstream.PackStream$Unpacker.unpackStructHeader(PackStream.java:471)
        at org.neo4j.driver.internal.messaging.PackStreamMessageFormatV1$Reader.read(PackStreamMessageFormatV1.java:352)
        at org.neo4j.driver.internal.connector.socket.SocketClient.send(SocketClient.java:113)
        at org.neo4j.driver.internal.connector.socket.SocketConnection.sync(SocketConnection.java:101)
        ... 18 more


<JMH had finished, but forked VM did not exit, are there stray running threads? Waiting 24 seconds more...>
<JMH had finished, but forked VM did not exit, are there stray running threads? Waiting 19 seconds more...>
<JMH had finished, but forked VM did not exit, are there stray running threads? Waiting 14 seconds more...>
<JMH had finished, but forked VM did not exit, are there stray running threads? Waiting 9 seconds more...>
<JMH had finished, but forked VM did not exit, are there stray running threads? Waiting 4 seconds more...>
<JMH had finished, but forked VM did not exit, are there stray running threads? Waiting 0 seconds more...>
<shutdown timeout of 30 seconds expired, forcing forked VM to exit>

# Run complete. Total time: 00:02:34

As a side node, several points regarding benchmark results:

  • NDP is significantly faster than default REST API on small result set
  • NDP became worse on bigger data size. With X = 100, NDP has same performance numbers as REST API.
  • When X = 500 it became even worse.

As I see, even if Result has stream-like API, currently driver fetch all records and then returns them.

But, anyway, NDP performance looks great, when they are no data transfer involved.

Create node benchmark.

Note: NDP and DB benchmarks share same top-level layer.
NDP - neo4j-java-driver is used as transport
DB - Unmanaged extension + HTTP + Kryo is used as transport

Benchmark                                Mode  Cnt  Score   Error  Units
CreateNodeBenchmark.createEmptyNodeDb    avgt    3  5.731 ± 6.670  ms/op
CreateNodeBenchmark.createEmptyNodeNdp   avgt    3  1.209 ± 0.635  ms/op
CreateNodeBenchmark.createEmptyNodeRest  avgt    3  2.338 ± 0.699  ms/op

Get single node benchmark

Same as above.

Benchmark                       Mode  Cnt  Score    Error  Units
GetNodesBenchmark.getNodesDb    avgt    3  6.311 ± 11.044  ms/op
GetNodesBenchmark.getNodesNdp   avgt    3  0.465 ±  0.402  ms/op
GetNodesBenchmark.getNodesRest  avgt    3  1.377 ±  0.316  ms/op

Please restore default values to call to get a node's property

With Neo3 and bolt the method for getting a property value from a node lost the ability to set a default value in case the property doesn’t exist in the node. That was a VERY useful feature. With the current implementation you end up taking code that effectively was (prior to Bolt) as simple and clear as:
String myValue = node.get(“myValue”,””)
to

String myValue = “"
if(node.containsKey(“myValue”)) { myValue = node.get(“myValue”).asString()}

Obviously its not a huge deal if you have to do it once, but when you have to do it frequently (as I am when migrating 2.3 code to bolt) then it is a bit of a pain and a source of potential errors.

BoltRequest doesn't map enumerated values when executing statements

In the code for org.neo4j.ogm.drivers.bolt.request.BoltRequest, lines 142 and below:

		BoltTransaction tx;
		try {
			String params = mapper.writeValueAsString(request.getParameters());
			TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {
			};
			HashMap<String, Object> parameterMap = mapper.readValue(params.getBytes(), typeRef);

			LOGGER.info("Request: {} with params {}", request.getStatement(), parameterMap);

			if (transactionManager.getCurrentTransaction() == null) {
				org.neo4j.ogm.transaction.Transaction autoCommitTx = transactionManager.openTransaction();
				tx = (BoltTransaction) autoCommitTx;
				StatementResult statementResult = tx.nativeBoltTransaction().run(request.getStatement(), parameterMap);
				tx.commit();
				tx.close();
				return statementResult;
			}
			tx = (BoltTransaction) transactionManager.getCurrentTransaction();
			return tx.nativeBoltTransaction().run(request.getStatement(), request.getParameters());

When transactionManager.getCurrentTransaction() == null, the code executes tx.nativeBoltTransaction().run(...) with parsed parameterMap variable. But for an existing transaction, the same code is called with request.getParameters() instead.

The run method eventually uses org.neo4j.driver.v1.Values.value(), that fails to parse a non primitive object. My understanding is that using the parsed parameter map should fix the issue.

A way to reproduce this bug is a transactional repository in which one of the methods receives an enum as parameter.

@Repository
@Transactional
public interface TestRepository {
   @Query("MATCH (x:RECORD {recordType: {0}}) RETURN x")
   public Set<Record> getRecordsOfType(RecordType recordType);
}

@NodeEntity(label = "RECORD")
public class Record {
    private RecordType recordType;
...
}

public enum RecordType {
...
}

README is not valid Java

The README mentions this

Driver driver = ( "bolt://localhost", AuthTokens.basic( "neo4j", "neo4j" ) );

That's not valid java. You forgot the leading GraphDatabase.driver

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.