在neo4j中创建节点,花时间通过java驱动程序

时间:2018-05-15 10:33:12

标签: neo4j

我正在使用neo4j-java driver Neo4j 中创建节点并借助以下密码查询。

String cipherQuery = "CREATE (n:MLObsTemp { personId: " + personId + ",conceptId: " + conceptId
                            + ",obsId: " + obsId + ",MLObsId: " + mlObsId + ",encounterId: " + encounterId + "}) RETURN n";

创建查询的功能

createNeo4JObsNode(String cipherQuery);

功能的实现

private void createNeo4JObsNode(String cipherQuery) throws Exception {
   try (ConNeo4j greeter = new ConNeo4j("bolt://localhost:7687", "neo4j", "qwas")) {
   System.out.println("Executing query : " + cipherQuery);

  try (Session session = driver.session()) {
   StatementResult result = session.run(cipherQuery);

  } catch (Exception e) {
   System.out.println("Error" + e.getMessage());
  }

 } catch (Exception e) {
  e.printStackTrace();
 }

}

使用以下代码与上述节点建立关系

String obsMatchQuery = "MATCH (m:MLObsTemp),(o:Obs) WHERE m.obsId=o.obsId CREATE (m)-[:OBS]->(o)";
        createNeo4JObsNode(obsMatchQuery);

        String personMatchQuery = "MATCH (m:MLObsTemp),(p:Person) WHERE m.personId=p.personId CREATE (m)-[:PERSON]->(p)";
        createNeo4JObsNode(personMatchQuery);

        String encounterMatchQuery = "MATCH (m:MLObsTemp),(e:Encounter) WHERE m.encounterId=e.encounterId CREATE (m)-[:ENCOUNTER]->(e)";
        createNeo4JObsNode(encounterMatchQuery);

        String conceptMatchQuery = "MATCH (m:MLObsTemp),(c:Concept) WHERE m.conceptId=c.conceptId CREATE (m)-[:CONCEPT]->(c)";
        createNeo4JObsNode(conceptMatchQuery);

平均创建节点需要13秒,建立关系需要12秒。我的数据库中有350k记录,我必须创建节点及其各自的关系。

如何改进我的代码?而且,这是使用bolt服务器和neo4j-java驱动程序在Neo4j中创建节点的最佳方法吗?

修改

我现在在我的代码中使用查询参数

 HashMap<String, Object> parameters = new HashMap<String, Object>();

         ((HashMap<String, Object>) parameters).put("personId", 1390);
         ((HashMap<String, Object>) parameters).put("obsId", 14001);
         ((HashMap<String, Object>) parameters).put("conceptId", 5978);
         ((HashMap<String, Object>) parameters).put("encounterId", 10810);
         ((HashMap<String, Object>) parameters).put("mlobsId", 2);



         String cypherQuery=
                 "CREATE (m:MLObsTemp { personId: $personId, ObsId: $obsId, conceptId: $conceptId, MLObsId: $mlobsId, encounterId: $encounterId}) "
                + "WITH m MATCH (p:Person { personId: $personId }) CREATE (m)-[:PERSON]->(p) "
                + "WITH m MATCH (e:Encounter {encounterId: $encounterId }) CREATE (m)-[:Encounter]->(e) "
                + "WITH m MATCH (o:Obs {obsId: $obsId }) CREATE (m)-[:OBS]->(o) "
                + "WITH m MATCH (c:Concept {conceptId: $conceptId }) CREATE (m)-[:CONCEPT]->(c) "
                + " RETURN m";

创建节点功能

 try {
  ConNeo4j greeter = new ConNeo4j("bolt://localhost:7687", "neo4j", "qwas");

  try {
   Session session = driver.session();
   StatementResult result = session.run(cypherQuery, parameters);
   System.out.println(result);
  } catch (Exception e) {
   System.out.println("[WARNING] Null Row");
  }

 } catch (Exception e) {
  e.printStackTrace();
 }

我也在执行索引以加快流程

  CREATE CONSTRAINT ON (P:Person) ASSERT P.personId IS UNIQUE
        CREATE CONSTRAINT ON (E:Encounter) ASSERT E.encounterId IS UNIQUE
        CREATE CONSTRAINT ON (O:Obs) ASSERT O.obsId IS UNIQUE
        CREATE CONSTRAINT ON (C:Concept) ASSERT C.conceptId IS UNIQUE

以下是1 cypher query-profile

的计划

现在性能有所改善,但并不显着。我使用的是neo4j-java-driver 1.6.1版。如何批量我的密码查询以进一步提高性能。

1 个答案:

答案 0 :(得分:2)

您应该尽量减少密码中的冗余工作。

MLObsTemp具有许多冗余属性,您正在搜索它以创建每个链接。关系无法为外键(节点ID)创建属性

我会推荐一个能完成所有事情的Cypher,并使用这样的参数......

CREATE (m:MLObsTemp) 
WITH m MATCH (p:Person {id:"$person_id"}) CREATE (m)-[:PERSON]->(p)
WITH m MATCH (e:Encounter {id:"$encounter_id"}) CREATE (m)-[:Encounter]->(e)
WITH m MATCH (c:Concept {id:"$concept_id"}) CREATE (m)-[:CONCEPT]->(c)
// SNIP more MATCH/CREATE
RETURN m

这样,Neo4j不必为每个关系重复找到m。您不需要ID属性,因为这实际上就是您刚创建的关系。 Neo4j在行走边缘(关系)方面非常有效,所以如果你需要id值,请关注关系。

提示:( Neo4j版本的里程可能非常多)

  • 内联几乎总是比WHERE(MATCH (n{id:"rawr"}) vs MATCH (n) WHERE n.id="rawr"
  • 更有效率
  • Parameters使频繁,类似的查询更有效率,因为Neo4j将缓存如何快速执行此操作(上述查询中使用的$thing_id语法。)此外,它还可以保护您免受Cypher注入(请参阅SQL injection
  • 从会话中,您可以创建一个事务(Session.run()实际上为每个运行调用创建一个事务)。您可以使用单个事务批处理多个Cyphers(甚至使用来自同一事务的先前Cyphers的结果),因为事务存储在内存中,直到您将其标记为成功并关闭它。请注意,如果您不小心,您的交易可能会因为&#34; outofmemory&#34;而失败。所以请记住定期/批次之间提交。 (提交批量的10k记录似乎是摄取大型数据集时的常态)