py2neo "ProtocolError: Server closed connection" when using Bolt - neo4j

Recently a script which uses py2neo package and connects via the Bolt protocol began failing unexpectedly with a ProtocolError: Server closed connection, and I'm struggling to understand why. Note the script works when using HTTP as the protocol.
The script pulls the Neo4j graph, augments it in Python and then attempts to push the relevant changes back to the database. The whole process takes about an hour, and was working reliably for quite some time, however the push stage recently starting failing.
If I create a toy example, bypasses the pull and augmentation, then the push works and thus I'm thinking the server closed the connection due to a timeout, however I can't find any timeout related parameter for Bolt in py2neo. Note I have set the HTTP socket timeout to be 9999 seconds (~ 2.75 hours),
from py2neo.packages.httpstream import http
http.socket_timeout = 9999
though my understanding of this is i) it's unrelated to Bolt and ii) the timeout is at the connection level which greatly exceeds the time the script ran.
For reference I'm using Neo4j v3.0.3 and py2neo v3.1.2. The stack-trace was:
File "/usr/local/lib/python2.7/dist-packages/py2neo/database/__init__.py", line 1017, in __exit__
self.commit()
File "/usr/local/lib/python2.7/dist-packages/py2neo/database/__init__.py", line 1059, in commit
self._post(commit=True)
File "/usr/local/lib/python2.7/dist-packages/py2neo/database/__init__.py", line 1291, in _post
self.finish()
File "/usr/local/lib/python2.7/dist-packages/py2neo/database/__init__.py", line 1296, in finish
self._sync()
File "/usr/local/lib/python2.7/dist-packages/py2neo/database/__init__.py", line 1286, in _sync
connection.fetch()
File "/usr/local/lib/python2.7/dist-packages/py2neo/packages/neo4j/v1/bolt.py", line 323, in fetch
raw.writelines(self.channel.chunk_reader())
File "/usr/local/lib/python2.7/dist-packages/py2neo/packages/neo4j/v1/bolt.py", line 174, in chunk_reader
chunk_header = self._recv(2)
File "/usr/local/lib/python2.7/dist-packages/py2neo/packages/neo4j/v1/bolt.py", line 157, in _recv
raise ProtocolError("Server closed connection")
ProtocolError: Server closed connection
and the stripped down Python code is of the form,
import py2neo
from py2neo.packages.httpstream import http
http.socket_timeout = 3600
graph = py2neo.Graph(
host='localhost',
bolt=True,
bolt_port=4096,
http_port=4095,
)
# Pull the graph from the Neo4j database via graph.run(...) statements,
# augments the graph etc.
# ...
# Exception is thrown when the following push transaction is executed.
with graph.begin() as tx:
statement = """
UNWIND {rows} AS row
WITH row.source AS source, row.target AS target
MATCH (s:Entity)
USING INDEX s:Entity(uuid)
WHERE s.uuid = source
MATCH (t:Entity)
USING INDEX t:Entity(uuid)
WHERE t.uuid = target
MATCH (s)-[r:FAVORITED]->(t)
DELETE r
"""
rows = [{
'source': '8267d7d0-a837-11e6-b841-22000bcec6a9',
'target': 'c6296c97-a837-11e6-b841-22000bcec6a9',
}]
tx.run(statement, rows=rows)
Does anyone have any suggestions as to how I can further debug this or what causes the connection to close? I've looked through the _recv function but it's not apparent why no data was received by the socket.
Looking through the Neo4j debug.log file the only possible related error was
java.io.IOException: Connection reset by peer
at sun.nio.ch.FileDispatcherImpl.read0(Native Method)
at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)
at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
at sun.nio.ch.IOUtil.read(IOUtil.java:192)
at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380)
at io.netty.buffer.PooledUnsafeDirectByteBuf.setBytes(PooledUnsafeDirectByteBuf.java:311)
at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:881)
at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:242)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:119)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:111)
at java.lang.Thread.run(Thread.java:745)
I've also checked the uptime of the service, and confirmed that it was running throughout the entire duration of the script (HH:MM:SS),
> ps -p "14765" -o etime=
16:55:31

I believe the issue is with:
tx.run(statement, rows=rows)
The second argument to CypherResoure.run() is a dictionary of parameters. You're passing them in as additional python params. See py2neo code.
Try:
tx.run(statement, {"rows": rows});

Related

Problems using python packages (Neomodel & py2neo) with Neo4j

I am having some issues using the Neomodel and py2neo clients with Neo4j. I have installed Neomodel and py2neo in seperate anaconda virtual environments and tested each individually. Neo4j is installed/docked using docker.
Neomodel
The code
from neomodel import (config, StructuredNode, StringProperty, IntegerProperty,UniqueIdProperty, RelationshipTo, RelationshipFrom)
config.DATABASE_URL = 'bolt://neo4j:password#localhost:7687'
class Country(StructuredNode):
code = StringProperty(unique_index=True, required=True)
# traverse incoming IS_FROM relation, inflate to Person objects
inhabitant = RelationshipFrom('Person', 'IS_FROM')
class Person(StructuredNode):
uid = UniqueIdProperty()
name = StringProperty(unique_index=True)
age = IntegerProperty(index=True, default=0)
# traverse outgoing IS_FROM relations, inflate to Country objects
country = RelationshipTo(Country, 'IS_FROM')
jim = Person(name='Jim', age=3).save()
jim.age = 4
jim.save() # validation happens here
jim.delete()
jim.refresh() # reload properties from neo
jim.id # neo4j internal id
While Neomodel generates the node viewed on the neo4j webapp. The node created is Jim with age=3 i.e. It does not seem to have recorded the fact that Jims age changed from 3 -> 4. Also, I am assuming that jim.delete() would have deleted the node which it did not neither. Lastly, it prompts the following error (below is a snippet of the last lines of the error).
Error
...
File "/Users/sjamal/.conda/envs/tneo/lib/python3.6/site-
packages/neomodel/core.py", line 452, in inflate
if db_property in node.properties:
AttributeError: 'Node' object has no attribute 'properties'
Now I did find this post where the user "Jack Daniel" mentioned that neomodel does not support neo4j 3. So I tried docking the Neo4j v.2.3 image but then I receive the following error (note that its a snippet of the last few lines of the error)
Error when docking image Neo4j 2.3
File "/Users/sjamal/.conda/envs/tneo/lib/python3.6/ssl.py", line 817, in __init__
self.do_handshake()
File "/Users/sjamal/.conda/envs/tneo/lib/python3.6/ssl.py", line 1077, in do_handshake
self._sslobj.do_handshake()
File "/Users/sjamal/.conda/envs/tneo/lib/python3.6/ssl.py", line 689, in do_handshake
self._sslobj.do_handshake()
OSError: [Errno 0] Error
Py2neo
I started looking into using p2neo due to the issues I had with Neomodel but I cannot seem to get my configurations right.
The code
from py2neo import Node, Relationship, Graph
graph = Graph("localhost", user='neo4j', password='password', bolt=None)
alice = Node("Person", name="Alice")
bob = Node("Person", name="Bob")
alice_knows_bob = Relationship(alice, "KNOWS", bob)
graph.create(alice_knows_bob)
Error
File "/Users/sjamal/.conda/envs/py2neo_test/lib/python3.6/site-packages/neo4j/bolt/connection.py", line 459, in acquire
connection = self.connector(address)
File "/Users/sjamal/.conda/envs/py2neo_test/lib/python3.6/site-packages/neo4j/v1/bolt.py", line 46, in <lambda>
pool = ConnectionPool(lambda a: connect(a, security_plan.ssl_context, **config))
File "/Users/sjamal/.conda/envs/py2neo_test/lib/python3.6/site-packages/neo4j/bolt/connection.py", line 601, in connect
raise ProtocolError("Connection to %r closed without handshake response" % (address,))
neo4j.bolt.connection.ProtocolError: Connection to ('localhost', 7687) closed without handshake response
Thanks to anyone looking into this. I would be happy to receive any suggestion or explanation on how to set up Py2neo irrespective if I get Neomodel to work or not.
So I have managed to solve my issue with Py2neo but not the issue I had with Neomodel. If I do find a way to get Neomodel working I will post it and either link to this post or post as a comment in this thread.
Py2neo solution with py2neo v4.0 and neo4j v3.o
I tried various combinations, starting with neo4j 2.3 together with different versions of py2neo such as 3.1.2 and then did the same with neo4j v3.0.
I am posting my script that I used to create the node and the graph connection as I was going mad when trying to figure out if I set up the configuration poorly or there was a bug in the package, driver etc.
Py2neo script
from py2neo import Node, Relationship, Graph
graph = Graph('http://localhost:7474/db/data',user='neo4j',pass word='password1234')
tx = graph.begin()
a = Node(label='hero',name='Sabri')
tx.create(a)
tx.commit()
Outdated driver py2neo v3.1.2 in tandem with Neo4j v3.4
As discussed in this Github issue report https://github.com/neo4j/neo4j-python-driver/issues/252 the user who reported the issue was using py2neo 3.1.2 together with Neo4jv3.4. The suspicion was that it was due to an outdated driver (v1.1) that came with py2neo 3.1.2. The new distribution of Neo4j v3.4 seems to come with the new driver 1.6.
Upgrading py2neo to v4.0 and sticking to latest version of Neo4j server i.e. v3.4
When doing this I ran into a different error
File "/Users/sjamal/.conda/envs/py2neo.v4/lib/python3.6/site-packages/py2neo/internal/http.py", line 26, in <module>
from neo4j.addressing import SocketAddress
ModuleNotFoundError: No module named 'neo4j.addressing'
It was discussed in this stackoverflow thread (ModuleNotFoundError: No module named 'neo4j.addressing' and ModuleNotFoundError: No module named 'neo4j') that the issue might be that the driver 1.6 driver might have to be manually installed through pip, which I did.
pip install neo4j-driver==1.6.2
I now received a new error where TypeError was caught when calling a map object.
File "/Users/sjamal/.conda/envs/py2neo.v4/lib/python3.6/site-packages/py2neo/internal/http.py", line 74, in fix_parameters
raise TypeError("Parameters of type {} are not supported".format(type(value).__name__))
TypeError: Parameters of type map are not supported
I found this github issue posted by speters-cmri https://github.com/technige/py2neo/issues/688 which contained the following github commit (https://github.com/technige/py2neo/compare/v4...CMRI-ProCan:v4) to resolve the issue by modifying a json.py script in the py2neo package
I ran my script again to add a test node and it ran without any issues.
If you are too lazy or simply too frustrated to go through a long explanation here is a summary
1. Make sure neo4j v3.0+ is installed. I suggest you look into docker to install neo4j using a docker image
2. pip install py2neo==v4.0
3. pip install neo4j-driver==1.6.2
4. Modify json.py file as described here https://github.com/technige/py2neo/compare/v4...CMRI-ProCan:v4
5. Run py2neo script outlined above

Error reading csv on remote server "Value `null` is not supported as key in maps, must be a non-nullable string."

I have a strange problem - I have a local neo4j instance v 2.3.8 and a remote server instance of neo4j v 3.1.4
I am in the process of rebuilding my graph on the remote server using the source files. This has been successful so far - I am able to import the csv files successfully on the remote server - I am accessing the remote server through the browser (remote http connection)
With literally the last file, I get the following error message on the remote server but the same works fine in my local neo4j instance:
Value null is not supported as key in maps, must be a non-nullable
string.
The cypher query is:
Load csv with headers from "srcfile3.csv" as line
WITH line
return line limit 2
The error message seems to be generated from this file in the neo4j code: https://fossies.org/linux/neo4j/community/bolt/src/main/java/org/neo4j/bolt/v1/messaging/Neo4jPack.java, if that helps.
Solution: Recreated the csv from the original xlsx - ensured all headers were in place and the file opened correctly. Thanks to /u/Tezra for the pointer

py2neo 3.1.2 connection problems

I am trying to commit a small graph of three nodes (a_py2neo_subgraph) to my graphene Neo4j server. I am using py2neo 3.1.2.
g = py2neo.Graph(server)
tx = g.begin()
tx.create(a_py2neo_subgraph)
tx.commit()
tx.finished()
Where "server" is the exact value given by Graphene (i.e. something like http://nick:password#hobby-hash.dbs.graphenedb.com:port/db/data/). In order to debug, I ran with py2neo watch and this was the info given by watch for my httpstream:
> GET server
< 200 OK [1287]
Then I get the following traceback:
Traceback (most recent call last):
File "C:/Users/petr.svarny/PycharmProjects/untitled/test.py", line 116, in <module>
tx = g.begin()
File "C:\Users\petr.svarny\untitled\lib\site-packages\py2neo\database\__init__.py", line 370, in begin
return self.transaction_class(self, autocommit)
File "C:\Users\petr.svarny\untitled\lib\site-packages\py2neo\database\__init__.py", line 1249, in __init__
self.session = driver.session()
File "C:\Users\petr.svarny\untitled\lib\site-packages\py2neo\packages\neo4j\v1\session.py", line 126, in session
connection = connect(self.address, self.ssl_context, **self.config)
File "C:\Users\petr.svarny\untitled\lib\site-packages\py2neo\packages\neo4j\v1\bolt.py", line 419, in connect
s = create_connection(host_port)
File "C:\Python27\Lib\socket.py", line 571, in create_connection
raise err
socket.error: [Errno 10060]
I already tried to set the socket timeout to 9999, did not help. I attempted to connect via telnet to the server and managed to do so without any problem. Similarly I am able to access the server address when I enter it into my browser. I also managed to run my code for a local Neo4j database.
Thank you for any suggestions.
I'm Judit from GrapheneDB. Can you check which version of py2neo are you using? The problem you have described looks like a common issue when moving from Py2neo v2 to v3. Since py2neo v3 supports Bolt protocol, you have to specify the bolt port or just tell the driver you're not using it.
If you don't want to use Bolt connection, your code should look like the following:
graph = Graph("http://USER:PASS#hobby-hash.dbs.graphenedb.com:port/db/data/", bolt = False)
If it's not your case, it'd be useful to know which version of Python/Py2neo/Neo4j are you using.
Cheers!
I had a similar problem with py2neo 3.1.2 and I could not get it to work even with the "bolt=False" switch.
I have switched to neorestclient 2.1.1 and now that works.

Can't connect to CFS node

I removed (or decommisioned, can't remember) a DSE analytics node (with IP 10.14.5.50) a couple of months ago. When I now try to execute a dse shark (CREATE TABLE ccc AS SELECT ...) query I now receiving:
15/01/22 13:23:17 ERROR parse.SharkSemanticAnalyzer: org.apache.hadoop.hive.ql.parse.SemanticException: 0:0 Error creating temporary folder on: cfs://10.14.5.50/user/hive/warehouse/mykeyspace.db. Error encountered near token 'TOK_TMP_FILE'
at org.apache.hadoop.hive.ql.parse.SemanticAnalyzer.getMetaData(SemanticAnalyzer.java:1256)
at org.apache.hadoop.hive.ql.parse.SemanticAnalyzer.getMetaData(SemanticAnalyzer.java:1053)
at org.apache.hadoop.hive.ql.parse.SemanticAnalyzer.analyzeInternal(SemanticAnalyzer.java:8342)
at shark.parse.SharkSemanticAnalyzer.analyzeInternal(SharkSemanticAnalyzer.scala:105)
at org.apache.hadoop.hive.ql.parse.BaseSemanticAnalyzer.analyze(BaseSemanticAnalyzer.java:284)
at shark.SharkDriver.compile(SharkDriver.scala:215)
at org.apache.hadoop.hive.ql.Driver.compile(Driver.java:342)
at org.apache.hadoop.hive.ql.Driver.runInternal(Driver.java:977)
at org.apache.hadoop.hive.ql.Driver.run(Driver.java:888)
at shark.SharkCliDriver.processCmd(SharkCliDriver.scala:347)
at org.apache.hadoop.hive.cli.CliDriver.processLine(CliDriver.java:413)
at shark.SharkCliDriver$.main(SharkCliDriver.scala:240)
at shark.SharkCliDriver.main(SharkCliDriver.scala)
Caused by: java.lang.RuntimeException: java.io.IOException: Error connecting to node 10.14.5.50:9160 with strategy STICKY.
at org.apache.hadoop.hive.ql.Context.getScratchDir(Context.java:216)
at org.apache.hadoop.hive.ql.Context.getExternalScratchDir(Context.java:270)
at org.apache.hadoop.hive.ql.Context.getExternalTmpFileURI(Context.java:363)
at org.apache.hadoop.hive.ql.parse.SemanticAnalyzer.getMetaData(SemanticAnalyzer.java:1253)
... 12 more
I guess the above error is due to my keyspace referring to the old node:
shark> DESCRIBE DATABASE mykeyspace;
OK
mykeyspace cfs://10.14.5.50/user/hive/warehouse/mykeyspace.db
Time taken: 0.997 seconds
Is there any way for me to fix this incorrect database path?
Tried (but failed) workaround to recreate the database: In cqlsh I created a keyspace thekeyspace and added a table thetable. I the opened up dse hive (and noticed that DESCRIBE DATABASE thekeyspace is giving me a correct cfs path). However, I am unable to drop the the database using DROP DATABASE thekeyspace.
Additional information:
I have no external tables in my keyspace.
Making the SELECT against the tables works.
Setting -hiveconf cassandra.host=WORKING_NODE_IP does not help.
The following commands return proper IP:s (ie. not X.X.X.50):
dsetool listjt
dsetool jobtracker
dsetool sparkmaster
I am getting the same error when I execute the query using dse hive.
No Shark variable is referring to X.X.X.50 when I execute set; in its REPL.
I am running DSE 4.5.
Stumbled across this page that says you need to TRUNCATE "HiveMetaStore"."MetaStore" (in cqlsh) after removing Hive nodes. That did the trick.

Neo4j: Java API IndexHits<Node>.size() is 0

I'm trying to use the Java API for Neo4j but I seem to be stuck at IndexHits. If I query the DB with Cypher using
START n=node:types(type="Process") RETURN n;
I get all 2087 nodes of type "Process".
In my application I have the following lines
Index<Node> nodeIndex = db.index().forNodes("types");
IndexHits<Node> hits = nodeIndex.get("type", "Process");
System.out.println("Node index size: " + hits.size());
which leads my console to spit out a value of 0. Here, db is of course an instance of GraphDatabaseService.
I expected an object that included all 2087 nodes. What am I doing wrong?
The .size() question is just the prelude to my iterator
for(Node process : hits) { ... }
but that does not much when hits.size() == 0. According to http://api.neo4j.org/1.9.2/org/neo4j/graphdb/index/IndexHits.html this should be possible, provided there is something in hits.
Thanks in advance for your help.
I figured it out. Man, I feel so embarrassed...
It so happens that I had set up the DB_PATH to my default data folder, whereas the default storage folder is the default data folder plus graph.db. When I tried to run the code from that corrected DB_PATH I got an error saying that a lock file was in place because the Neo4j server was running. After shutting it down it worked perfectly.
So, if you happen to see the following error, just stop the server and run the code again:
Caused by: org.neo4j.kernel.StoreLockException: Could not create lock file
at org.neo4j.kernel.StoreLocker.checkLock(StoreLocker.java:74)
at org.neo4j.kernel.StoreLockerLifecycleAdapter.start(StoreLockerLifecycleAdapter.java:40)
at org.neo4j.kernel.lifecycle.LifeSupport$LifecycleInstance.start(LifeSupport.java:491)
I found on several forums that you cannot run the Neo4j server and use the Java API to query it at the same time.

Resources