neo4j-ogm 2.1.1的性能问题,一次性创建节点和相关节点的密码查询

时间:2017-02-08 16:55:29

标签: java performance neo4j neo4j-ogm

我有一个密码查询,一次创建以下内容:
- 500个主节点
- 与每个主节点相关的12个节点(包括关系)
- 两个现有节点上的2个关系(500个主节点将与相同的两个节点相关)

最后,它将创建:
- 7000个节点
- 7000个关系

在查询结束时,我有这个语句来返回所有创建的实体:

MATCH (n:Primary) WHERE n.id IN {ids} WITH n MATCH path=(n)-[*0..]->() RETURN path

使用位于同一网络上另一台计算机上的远程neo4j数据库,查询大约需要15秒。

我期待得到比这更好的结果,所以我做了一些分析,这就是我得到的:

85.0% - 10,816 ms org.neo4j.ogm.session.Neo4jSession.query
  85.0% - 10,816 ms org.neo4j.ogm.session.delegates.ExecuteQueriesDelegate.query
    85.0% - 10,816 ms org.neo4j.ogm.session.delegates.ExecuteQueriesDelegate.executeAndMap
      72.3% - 9,202 ms org.neo4j.ogm.context.GraphEntityMapper.map
        63.0% - 8,019 ms org.neo4j.ogm.context.GraphEntityMapper.map
          52.1% - 6,628 ms java.lang.Class.isAssignableFrom
            10.8% - 1,371 ms org.neo4j.ogm.context.GraphEntityMapper.mapEntities
              0.1% - 9,967 µs org.neo4j.ogm.context.MappingContext.getNodeEntity

因此,根据我的理解,查询在ExecuteQueriesDelegates类的executeAndMap方法中执行,并立即返回响应。

在此之后,这是使用GraphEntityMapper从响应中创建实体。

所以我得出结论,查询本身是在合理的时间内执行的(少于2秒 - 我通过直接从REST客户端发布查询来验证)但超过70%的时间用于转换对模型实体的响应结果。

所以我认为这种转换需要一些时间才是正常的,但似乎花了太多时间进行以下测试:

if ... type.isAssignableFrom(o.getClass())

所以我不确定是否可以对neo4j-ogm方面做任何改进。与此同时,是否有任何可以帮助我提高绩效的解决方法?

02/10/2017其他信息

上述分析的结果是通过使用采样设置完成的。

我使用仪器设置完成了新的测量,这里的结果与最后的结果略有不同。对于这个测试,我只定义了200个主节点,因为我得到了500个异常(花费的时间太长)。

93.6% - 56,585 ms - 1 inv. org.neo4j.ogm.session.Neo4jSession.query
  93.6% - 56,585 ms - 1 inv. org.neo4j.ogm.session.delegates.ExecuteQueriesDelegate.query
    93.6% - 56,585 ms - 1 inv. org.neo4j.ogm.session.delegates.ExecuteQueriesDelegate.executeAndMap
      64.3% - 38,875 ms - 1 inv. org.neo4j.ogm.context.GraphEntityMapper.map
        46.7% - 28,229 ms - 9,800 inv. org.neo4j.ogm.context.GraphEntityMapper.map
          12.4% - 7,527 ms - 14,021,770 inv. org.neo4j.ogm.context.MappingContext.getNodeEntity
          9.8% - 5,918 ms - 9,800 inv. org.neo4j.ogm.context.GraphEntityMapper.mapEntities
          3.4% - 2,067 ms - 14,021,770 inv. java.lang.Class.isAssignableFrom
          2.7% - 1,621 ms - 14,021,770 inv. java.util.Iterator.next
          2.6% - 1,552 ms - 14,021,770 inv. java.lang.Object.getClass
          2.5% - 1,523 ms - 14,031,570 inv. java.util.Iterator.hasNext
          0.2% - 116 ms - 984,900 inv. java.util.List.add
          0.2% - 107 ms - 984,900 inv. java.lang.Class.cast
          0.0% - 2,173 µs - 9,800 inv. java.util.Set.iterator
          0.0% - 1,731 µs - 9,800 inv. java.util.ArrayList.<init>
          0.0% - 1,170 µs - 9,800 inv. java.util.List.isEmpty

我们可以在这里看到,大部分时间都不是通过调用isAssignableFrom方法而花费的。

如果我找到了什么,我会继续调查并随时通知您。

1 个答案:

答案 0 :(得分:3)

这里有一些事情发生。

大约35%的总时间用于从数据库中提取已完成的响应并将其转换为简单的NodeEdge表示形式。我怀疑大部分时间花在等待IO

接下来,映射阶段开始。在您的情况下,查询返回近10,000个对象,其中包括NodeEdge个对象。在映射上下文中查找每个Node,以确定它是否已存在,如果不存在则更新。此查找将Node引用链接到域中的对象。但是,您会看到getNodeEntity有超过1400万次来电,这需要一些解释。

大多数调用是在处理响应中的Edge元素时进行的。这些中的每一个都需要在映射上下文中为开始节点和结束节点进行额外查找,以便可以在正确的域对象上设置引用。但是,如果在此过程中发现域对象在集合或数组中维护了特定关系,则在发现每个关系时,不会立即更新集合或数组。相反,集合中的关系集合在一起,并且更新域对象将延迟到设置任何单值引用之后。

然后,如上所述,从先前收集的Edge个对象列表中进行基于集合的引用的分配。遗憾的是,相关域对象不在这些Edge对象上维护(仅限数据库节点ID)。因此,这需要从映射上下文中对相关域对象进行另一轮查找。这显然可以避免,因为他们已经被查过了一次。

我已经为我们提出了一张机票,让我们看看这个。 https://github.com/neo4j/neo4j-ogm/issues/327