代码之家  ›  专栏  ›  技术社区  ›  zakmck

Neo4j,带Cypher命令的批量加载

  •  3
  • zakmck  · 技术社区  · 7 年前

    我是Neo4j的新手,一定有一些基础知识我不懂。

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

    // 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 回复  |  直到 7 年前
        1
  •  1
  •   sjc    7 年前

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

    单独匹配边缘可能更快。在我的原始基准测试中,我看到了24毫秒与15毫秒的差异(编辑:这个基准测试是可疑的):

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

    另一种选择是使用展开。我使用BOLT接口发送更少的事务,但不使用批插入器。请原谅我在这里复制的Python实现,希望您可以将其与Javascript Neo4j驱动程序文档一起查看,以对其进行转换。

    payload = {"list":[{"a":"Name1","b":"Name2"},{"a":"Name3","b":"Name4"}]}
    
    statement = "UNWIND {list} AS d "
    statement += "MATCH (A:Person {name: d.a}) "
    statement += "MATCH (B:Person {name: d.b}) " 
    statement += "MERGE (A)-[:KNOWS]-(B) "
    
    tx = session.begin_transaction()
    tx.run(statement,payload)
    tx.commit()
    
        2
  •  1
  •   zakmck    4 年前

    我认为值得报告我在这方面的经验。

    我遵循了@sjc的建议,尝试了放松。然而,这并不是那么简单,因为Cypher不允许您参数化节点标签或关系类型(我有十几个标签和关系类型)。但最终,我能够遍历所有可能的类型,并向每个展开块发送足够的项目(大约1000个)。

    在我看来,使用UNWIND的代码要快得多,但还不够快(在一台像样的PC上,有几百万个节点,应该可以,但在数亿个或更多节点上,应该不是很好)。

    插入器组件的速度要快得多(上传100万到200万个节点需要几秒钟),尽管它需要关闭HTTP访问,而且我对它对Lucene 5.4的依赖性有很多问题,因为我需要在使用Lucene 6的应用程序(生成数据)中使用它,当我试图在类路径中简单地将5.4与6交换时,发生了可怕的事情。我看过了 there is some mechanism to make this possible ,但这似乎并不容易,当然也没有很好的记录。