【问题标题】:Neo4j Load CSV Import StallingNeo4j 加载 CSV 导入停滞
【发布时间】:2015-06-28 13:18:02
【问题描述】:

在玩弄玩具数据集之后,这是我第一次尝试使用与工作项目相关的数据。简而言之,在将我几乎所有的数据都输入 Neo4j 之后,我的最后一个查询就停止了。请参阅屏幕截图。

注意:我通过将查询粘贴到浏览器工具中来制作查询原型,但我的长期计划是将所有命令保存在 .cql 文件中,我可以在我的工作站上编写脚本以便执行夜间分析。

为了给我的问题添加上下文,我正在我的 macbook 上进行原型设计。

  • 8GB 内存
  • 2.2 GHz 英特尔酷睿 i7
  • osx 10.9.5
  • 2.2.0 社区

我正在处理的文件(行/列)。我没有导入每一列,只是更容易检查我当前的数据集。

  • Ability.csv = 3/1
  • brm.csv = 276992/34
  • cont.sv = 80093/17
  • email chain.csv = 199143/34(这是我唯一无法获取的数据)
  • email first last.csv = 77849/20
  • recs.csv = 77962/20
  • templates_topics.csv = 29/3
  • templates.csv = 49/4
  • topics.csv = 13/1
  • 供应商 = 5/1

我为 neo4j 手动设置的唯一配置选项是在 neo4j-wrapper.conf 中,我将 wrapper.java.initmemorywrapper.java.maxmemory 设置为 4096。在四处寻找类似的问题后,我这样做了。

我做出这些更改是因为在浏览器中,我收到错误消息,指出在处理我的查询时数据库已断开连接。

最后,由于我的数据与工作相关,我无法提供测试数据。但是,我可以链接到我的密码查询。

Constraint and LOAD CSV .cql file

任何帮助和建议将不胜感激。我非常有信心这是我的用户错误,但对于我的下一步,我肯定已经上路了。

【问题讨论】:

  • 在上一个 LOAD CSV 语句中,您使用 Email:cid 作为属性,而您的约束位于 Email:msgid
  • 很好,让我看看情况如何。
  • 这一次,当我尝试从 cypher.cql 文件的第 111 行开始执行命令时,我在浏览器中收到“数据库已断开连接”警告。从命令行运行该文件会带来任何性能改进吗?
  • 要关闭循环,当我从命令行运行整个脚本时,在修复复制/粘贴中的拼写错误后,我能够将所有数据放入数据库中。
  • 在导入数据时,您对 shell 的体验要好得多。

标签: neo4j cypher


【解决方案1】:

避免在 LOAD CSV 中急切加载。它不尊重定期提交。请参阅 Mark Needham 的 article 以获得详尽的解释。

【讨论】:

  • 我确实引用了那篇文章几次。我的第一个问题(在发布之前)是我使用MERGE 不考虑。我认为使用 MATCH + MERGE 会变得更好,但我确信仍有需要重构的地方。
  • 您是否尝试过使用脚本“分而治之”,您可能可以确定哪个部分是有问题的部分,并使用 EXPLAIN / PROFILE 功能更好地了解导致问题的原因。尝试(例如)使用关系分割节点创建,这样您可能可以删除有问题的 MERGE。
【解决方案2】:

我会将这个拆分为一次创建节点并(每一秒)创建关系:

USING PERIODIC COMMIT 10000
LOAD CSV WITH HEADERS FROM "file:///Users/btibert/Dropbox/Projects/bentley-search-neo4j/data/templates.csv" AS row
WITH row
MATCH (r:Vendor {name:row.vendor})
WITH row, r
MERGE (p:Template {name:row.template_clean})
MERGE (v:Version {version:row.template_ver})
MERGE (p)-[:FROM_VERSION]->(v)
MERGE (p)-[:CREATED_BY]->(r);

您可以清楚地看到计划中的Eager操作。

我的意思是如果你只有几千行也没关系。但如果它达到数十万或数百万,那么将所有数据拉入需要更多内存。

+----------------+------------------------------------+------------------------------------------------------------------------------------------------+
|       Operator |                        Identifiers |                                                                                          Other |
+----------------+------------------------------------+------------------------------------------------------------------------------------------------+
|    EmptyResult |                                    |                                                                                                |
| UpdateGraph(0) | anon[270], anon[301], p, r, row, v |                                                                                   MergePattern |
| UpdateGraph(1) |            anon[270], p, r, row, v |                                                                                   MergePattern |
| UpdateGraph(2) |                       p, r, row, v | MergeNode; row.template_clean; :Template(name); MergeNode; row.template_ver; :Version(version) |
|          Eager |                             r, row |                                                                                                |
|    SchemaIndex |                             r, row |                                                                      row.vendor; :Vendor(name) |
|        LoadCSV |                                row |                                                                                                |
+----------------+------------------------------------+------------------------------------------------------------------------------------------------+

对于非关键属性,我可能会将其更改为 ON CREATE SET 变体: 此外,如果每个学生有多个行,您可以使用 WITH DISTINCT toInt(row.pidm) as pidm, .... 来减少它必须运行的合并次数。

LOAD CSV WITH HEADERS FROM "recs.csv" AS row
WITH row
MERGE (s:Student {pidm:toInt(row.pidm)})
ON CREATE SET s.hash_pidm=toInt(row.hash_pidm), ....;

这个我会分成两个语句,每个关系一个,否则你可能会得到太多的匹配: (而且你不需要WITHs)

LOAD CSV WITH HEADERS FROM "...recs.csv" AS row
WITH row
MATCH (s:Student {pidm: toInt(row.pidm)} )
MATCH (v:Vendor {name: row.vendor} )
MATCH (a:Ability {name: row.ability} )
WITH row, s, v, a
MERGE (s)-[:PURCHASED_FROM]->(v)
MERGE (s)-[:HAS_ABILITY]->(a);

会变成:

LOAD CSV WITH HEADERS FROM "...recs.csv" AS row
MATCH (s:Student {pidm: toInt(row.pidm)} )
MATCH (v:Vendor {name: row.vendor} )
MERGE (s)-[:PURCHASED_FROM]->(v);


LOAD CSV WITH HEADERS FROM "...recs.csv" AS row
MATCH (s:Student {pidm: toInt(row.pidm)} )
MATCH (a:Ability {name: row.ability} )
MERGE (s)-[:HAS_ABILITY]->(a);

在这里我也会自己创建联系人。 (再次使用 ON CREATE SET) 并在单独的语句中做学生关系:

LOAD CSV WITH HEADERS FROM "....cont.csv" AS row
MERGE (c:Contact {cid:row.cid}) ON CREATE SET ....;

LOAD CSV WITH HEADERS FROM "...cont.csv" AS row
MATCH (s:Student {pidm:toInt(row.pidm)} )
MATCH (c:Contact {cid:row.cid})
MERGE (s)-[:HAS_CONTACT]->(c);

我也会把这个分成两个陈述:

LOAD CSV WITH HEADERS FROM "...cont.csv" AS row
WITH row WHERE toInt(row.seqnum) = 1
MATCH (s:Student {pidm:toInt(row.pidm)}) 
MATCH (f:Contact {cid:row.first_cont})
MERGE (s)-[:FIRST]->(f);

LOAD CSV WITH HEADERS FROM "...cont.csv" AS row
WITH row WHERE toInt(row.seqnum) = 1
MATCH (s:Student {pidm:toInt(row.pidm)}) 
MATCH (l:Contact {cid:row.last_cont})
MERGE (s)-[:LAST]->(l);

将此拆分为电子邮件创建,然后通过 msg-id 将其连接到学生:

LOAD CSV WITH HEADERS FROM "...brm.csv" AS row
MERGE (e:Email {msgid:row.msgid}) ON CREATE SET ... ;

LOAD CSV WITH HEADERS FROM "file:///Users/btibert/Dropbox/Projects/bentley-search-neo4j/data/brm.csv" AS row
MATCH (s:Student {pidm:toInt(row.pidm)}) 
MATCH (e:Email {msgid:row.msgid})
MERGE (s)-[:WAS_SENT]->(e);

HTH 迈克尔

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-19
    相关资源
    最近更新 更多