嗨,当我试图创建/合并节点和关系时,我收到了以下错误。它并不总是发生,但偶尔会发生一次。
CypherError:发生意外故障,请参阅数据库日志中的详细信息,参考编号eaf50bff-deca-4055-9450-6a76c31534e4。
这是回溯:
---------------------------------------------------------------------------
CypherError Traceback (most recent call last)
<ipython-input-21-9700f3a5d3fa> in <module>()
7 tx.success = True
8 #tx.close()
----> 9 session.close()
/databricks/python/local/lib/python2.7/site-packages/neo4j/v1/session.pyc in close(self)
522 """
523 if self.last_result:
--> 524 self.last_result.buffer()
525 if self.transaction:
526 self.transaction.close()
/databricks/python/local/lib/python2.7/site-packages/neo4j/v1/session.pyc in buffer(self)
246 if self.connection and not self.connection.closed:
247 while not self._consumed:
--> 248 self.connection.fetch()
249 self.connection = None
250
我创建/合并的代码如下:
for chunk in chunk_list:
with session.begin_transaction() as tx:
for record in chunk:
tx.run("MERGE (source:UID {userid : {m}, timestamp: {a}})"
"MERGE (target:UID {userid : {n}, timestamp: {a}})"
"MERGE (source)-[:HasConnection]-(target)", {"m": record.source, "n": record.target, "a": record.unix_timestamp_s})
tx.success = True
#tx.close()
session.close()
chunk_list是一个包含多个记录列表的列表。chunk_list中的每个列表都有多个行(大约10000行),每一行包含三个列、源、目标和时间戳。
对于chunk_list中的每个列表,我们将打开一个会话,然后执行合并操作,然后关闭会话。
当图超过1000万个节点时,问题就会发生。让我们假设,对于第一天,chunk_list有400万行,它可以正常工作,对于第2天,如果chunk_list有400万行,它也可以正常工作。但是,如果在第3天,Neo4j图中有300万行,节点总数超过1,000万,那么问题就开始发生了。
发布于 2017-01-08 08:17:51
发生这种情况是因为数据库耗尽了记录在日志中的磁盘空间。
发布于 2017-01-04 17:28:24
其中一个原因是执行起来花了这么长时间,因为您的查询没有执行您认为它正在做的事情。
进行合并就像尝试首先进行匹配,如果没有找到匹配,则执行创建。
在您的评论中,您说在合并操作期间时间戳应该更改,所以您真正想要做的是更新具有相同userid的节点的属性,但这不是您的合并所要做的。
您的合并首先尝试将a :UID节点与给定的userid和时间戳匹配,但图中不会有这样的节点,因为时间戳是new...there,它将是一个具有相同用户in但具有不同时间戳的:UID节点,因此将找不到匹配,将创建一个全新的:UID节点,该节点与现有节点具有相同的用户in,并创建新的时间戳。
因此,您的合并总是要创建新节点,而不是在现有节点上匹配。合并本身永远不会更新属性值,所以永远不要试图以这种方式使用它。
要执行匹配和更新,只需要根据要匹配的现有节点上的最小唯一属性进行合并,然后使用SET更新属性,如下所示:
for chunk in chunk_list:
with session.begin_transaction() as tx:
for record in chunk:
tx.run("MERGE (source:UID {userid : {m}})"
"SET source.timestamp = {a}"
"MERGE (target:UID {userid : {n}})"
"SET target.timestamp = {a}"
"MERGE (source)-[:HasConnection]-(target)", {"m": record.source, "n": record.target, "a": record.unix_timestamp_s})
tx.success = True
#tx.close()
session.close()
此外,为了确保合并速度快,您需要对UID(Userid)具有索引或唯一的约束,否则neo4j必须执行标签扫描才能找到节点,这对于图的大小来说太慢了。
编辑
我还没有在Neo4j中使用Python,但我不确定这种循环是否是处理多条记录的正确方法,因为它看起来将运行给定Cypher段的大量副本。5行Cypher似乎是extreme...ideally,您应该使用Cypher代码同时对所有行(或至少每块行)进行操作,您的输入可以很容易地转换为行执行。
更好的方法可能是使用循环生成对象列表(具有"m“和"n”属性),并将列表和单个时间戳作为参数提交给查询。
然后,您可以将Cypher中的列表解压回行,并使用该列表。因此,如果"row“是对象参数的列表,而"a”仍然是unix时间戳参数,则Cypher段看起来如下:
UNWIND {row} as line
MERGE (source:UID {userid : line.m})
SET source.timestamp = {a}
MERGE (target:UID {userid : line.n})
SET target.timestamp = {a}
MERGE (source)-[:HasConnection]-(target)
https://stackoverflow.com/questions/41454933
复制