Cypher 查询删除属性导致 neo4j-shell 中的内存不足错误

Posted

技术标签:

【中文标题】Cypher 查询删除属性导致 neo4j-shell 中的内存不足错误【英文标题】:Cypher query removing properties results in out-of-memory error in neo4j-shell 【发布时间】:2015-08-12 02:52:31 【问题描述】:

我有一个包含超过 1500 万个节点的大型网络。我想使用 neo4-shell 中的 Cypher 查询从所有这些属性中删除属性“CONTROL”。

如果我尝试执行以下任何操作:

MATCH (n) WHERE has(n.`CONTROL`) REMOVE n.`CONTROL` 返回计数(n); MATCH (n) WHERE has(n.`CONTROL`) REMOVE n.`CONTROL`; 匹配 (n) 删除 n.`CONTROL`;

系统返回:

服务器线程发生错误;嵌套异常是: java.lang.OutOfMemoryError: Java 堆空间

即使是下面的查询也会给出 OutOfMemoryError:

匹配 (n) 删除 n.`CONTROL` 返回 n.`ID` LIMIT 10;

作为测试,以下确实正确执行:

MATCH (n) WHERE has(n.`CONTROL`) 返回计数 (n);

返回 16636351。

一些细节:

内存限制取决于以下设置:

wrapper.java.maxmemory (conf/neo4j-wrapper.conf) neostore..._memory (conf/neo4j.properties)

通过在两个文件中将这些值设置为总计 28 GB,生成大约 45 GB 的 java_pidXXX.hprof 文件 (wrapper.java.additional=-XX:+HeapDumpOnOutOfMemoryError)。

我能google 的唯一线索是:

...您使用 Neo4j-Shell,它只是一个操作工具,只是在发回之前收集内存中的数据,它从来没有打算处理巨大的结果集。

真的不能使用 neo4j-shell 和 cypher 删除大型网络中的属性吗?还是我做错了什么?

PS

附加信息:

Neo4j 版本:2.1.3

Java 版本:Java(TM) SE Runtime Environment (build 1.7.0_76-b13) 和 OpenJDK Runtime Environment (IcedTea 2.5.4) (7u75-2.5.4-1~trusty1)

数据库为 7.4 GB(16636351 个节点,14724489 个关系)

属性“CONTROL”为空,即,它只是为所有节点定义,而没有实际分配属性值。

data/console.log 中的异常示例:

java.lang.OutOfMemoryError:Java 堆空间 将堆转储到 java_pid20541.hprof ... 转储文件不完整:文件大小限制 线程“GC-Monitor”中的异常 线程“pool-2-thread-2”中的异常 java.lang.OutOfMemoryError:Java 堆空间 在 java.util.Arrays.copyOf(Arrays.java:2271) 在 java.lang.StringCoding.safeTrim(StringCoding.java:79) 在 java.lang.StringCoding.access$300(StringCoding.java:50) 在 java.lang.StringCoding$StringEncoder.encode(StringCoding.java:305) 在 java.lang.StringCoding.encode(StringCoding.java:344) 在 java.lang.StringCoding.encode(StringCoding.java:387) 在 java.lang.String.getBytes(String.java:956) 在 ch.qos.logback.core.encoder.LayoutWrappingEncoder.convertToBytes(LayoutWrappingEncoder.java:122) 在 ch.qos.logback.core.encoder.LayoutWrappingEncoder.doEncode(LayoutWrappingEncoder.java:135) 在 ch.qos.logback.core.OutputStreamAppender.writeOut(OutputStreamAppender.java:194) 在 ch.qos.logback.core.FileAppender.writeOut(FileAppender.java:209) 在 ch.qos.logback.core.OutputStreamAppender.subAppend(OutputStreamAppender.java:219) 在 ch.qos.logback.core.OutputStreamAppender.append(OutputStreamAppender.java:103) 在 ch.qos.logback.core.UnsynchronizedAppenderBase.doAppend(UnsynchronizedAppenderBase.java:88) 在 ch.qos.logback.core.spi.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:48) 在 ch.qos.logback.classic.Logger.appendLoopOnAppenders(Logger.java:273) 在 ch.qos.logback.classic.Logger.callAppenders(Logger.java:260) 在 ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:442) 在 ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:396) 在 ch.qos.logback.classic.Logger.warn(Logger.java:709) 在 org.neo4j.kernel.logging.LogbackService$Slf4jToStringLoggerAdapter.warn(LogbackService.java:243) 在 org.neo4j.kernel.impl.cache.MeasureDoNothing.run(MeasureDoNothing.java:84) java.lang.OutOfMemoryError:Java 堆空间 在 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.addConditionWaiter(AbstractQueuedSynchronizer.java:1857) 在 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039) 在 java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1079) 在 java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:807) 在 java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 在 java.lang.Thread.run(Thread.java:745) 线程“Statistics Gatherer [primitives]”中的异常 java.lang.OutOfMemoryError:Java 堆空间 线程“RMI RenewClean-[10.65.4.212:42299]”中的异常 java.lang.OutOfMemoryError:Java 堆空间 线程“RMI RenewClean-[10.65.4.212:43614]”中的异常 java.lang.OutOfMemoryError: Java heap space

【问题讨论】:

【参考方案1】:

请看这里:http://jexp.de/blog/2013/05/on-importing-data-in-neo4j-blog-series/

要使用 Cypher 更新数据,还需要考虑交易规模。对于嵌入式案例,批处理事务将在本系列的下一部分中讨论。对于通过 Neo4j REST API 进行的远程执行,需要记住一些重要的事情。特别是对于大型索引查找和匹配结果,查询可能会更新数十万个元素。然后可以在更新操作之前放置一个使用 WITH 和 SKIP/LIMIT 的分页机制。

MATCH (m:Movie)<-[:ACTED_IN]-(a:Actor)
WITH a, count(*) AS cnt
SKIP offset LIMIT pagesize
SET a.movie_count = cnt
RETURN count(*)

以 pagesize=20000 运行并增加 offset=0,20000,40000,...直到查询返回计数

所以在你的情况下,重复这个直到它返回 0 行。您也可以将限制增加到 1M。

MATCH (n) WHERE has(n.`CONTROL`) 
WITH n
LIMIT 100000
REMOVE n.`CONTROL` 
RETURN COUNT(n);

【讨论】:

以上是关于Cypher 查询删除属性导致 neo4j-shell 中的内存不足错误的主要内容,如果未能解决你的问题,请参考以下文章

Cypher索引约束

如何使用Cypher返回节点的所有属性?

如何将值推送到 Cypher 中的属性数组?

如何在使用 cypher 使用 UNWIND 进行迭代时删除关系

Cypher:使用 WHERE 子句或 MATCH 属性定义进行精确匹配?

在 Cypher 中,如果关系不存在,我该如何创建关系;如果确实如此,请更新属性