Neo4j,使用Cypher命令批量加载

时间:2017-10-04 22:39:27

标签: java neo4j cypher

我是Neo4j的新手,必须有一些我对基础知识不了解的东西。

我在Java中有很多对象,我想用它们来填充Neo4j图,使用Java驱动程序和Cypher。我的代码是这样的:

// nodes
for ( Person person: persons )
  session.run ( String.format ( 
    "CREATE ( :Person { id: '%s', name: \"%s\", surname: \"%s\" })",
    person.getId(), person.getName(), person.getSurname ()
  ));

// relations
session.run ( "CREATE INDEX ON :Person(id)" );

for ( Friendship friendship: friendships )
  session.run ( String.format ( 
    "MATCH ( from:Person { id: '%s' } ), ( to:Person { id: '%s' } )\n" +
    "CREATE (from)-:KNOWS->(to)\n",
    friendship.getFrom().getId(), 
    friendship.getTo().getId() 
  )); 

(事实上,它稍微复杂一点,因为我有十几个节点类型和大约相同数量的关系类型)。

现在,这非常缓慢,例如加载300k节点和1M关系超过1小时(在相当快的MacBookPro上,Neo4j占用12 / 16GB RAM)。

我做错了吗?我应该使用batch inserter吗? (我希望能够通过网络访问graphDB)。我会通过将更多插入分组到一个事务中来获得某些东西吗? (从文档中看,事务似乎只对回滚和隔离需求有用)。

2 个答案:

答案 0 :(得分:0)

我来自Python中的Neo4j,但我认为这里的问题是你的Cypher命令。我有两个建议。

分别匹配边缘可能会更快。在我的原始基准测试中,我看到24ms与15ms相差(编辑:这个基准是可疑的):

    SiteSelectionViewController *sitesController;
    sitesController = [[SiteSelectionViewController alloc] init];
    [sitesController setConfData:self.confData];
    [sitesController setConfInitData:self.confInitData];
    [self.navigationController pushViewController:sitesController animated:YES];
    [sitesController release];

另一种选择是使用UNWIND。我在BOLT接口中使用它来发送更少的事务但不使用批量插入器。原谅我在这里复制的Python实现,希望你可以看看这个以及Javascript Neo4j驱动程序文档来转换它。

MATCH ( from:Person { id: '%s' } )
MATCH ( to:Person { id: '%s' } )
CREATE (from)-:KNOWS->(to)

答案 1 :(得分:0)

我认为值得报道我的经验。

我已经按照@sjc建议并尝试使用UNWIND。但是,这并不是那么简单,因为Cypher不允许您参数化节点标签或关系类型(我有十几种标签和关系类型)。但最终,我能够遍历所有可能的类型并向每个UNWIND块发送足够的项目(大约1000个)。

在我看来,使用UNWIND的代码速度要快得多,但还不够快(在一台体面的PC上应该没问题,并且有几百万个节点,对数亿个节点不太好,或者更多)。

插入器组件要快得多(上传1-2百万个节点几秒钟),虽然它需要降低HTTP访问权限并且我对Lucene 5.4的依赖性存在很多问题,因为我需要在使用Lucene 6的应用程序(生成数据)中使用,当我尝试在类路径中简单地用5.4交换5.4时发生了可怕的事情。我在那个there is some mechanism to make this possible附近,但它看起来并不容易,当然也没有那么好记录。

我绝对不会期望所有这些麻烦都能有效地执行这样的基本操作。