为什么在添加相同标签的更多节点时,findOne(<id>,<depth>)的性能会慢得令人无法接受?

时间:2016-04-07 22:37:01

标签: neo4j spring-boot spring-data-neo4j-4 neo4j-ogm

CONTEXT

我一直在开发一个由Neo4j数据库支持的spring boot网站。它旨在作为大学课程搜索系统。 (相关的结构是课程有模块组,有模块,与科目有关等......)

@JsonIdentityInfo(generator=JSOGGenerator.class)
public class Course extends DomainObject {
  @NotNull private String name;
  @NotNull private String courseCode;
  private String description;
  private School school;

  @Convert(AttendanceTypeConverter.class)
  private E_AttendanceType attendanceType;

  @Convert(CourseTypeConverter.class)
  private E_CourseType courseType;

  @Convert(SandwichYearTypeConverter.class)
  private E_SandwichYearType sandwichYearType;

  @Relationship(type = "COURSE_DESCRIPTION_FOR", direction =     Relationship.OUTGOING)
  private Set<CourseYearDescription> courseYearDescription;

  @Relationship(type = "COURSE_REQUISITES_SET_FOR", direction =  Relationship.OUTGOING)
  private Set<EntryRequirementsSet> entryRequirementsSets;

  @Relationship(type = "RUNS_COURSE", direction = Relationship.OUTGOING)
  Set<MemberOfFaculty> courseRunners;

对于课程页面,我需要填充课程的所有复杂字段,以便它们可以显示在页面上。我通过GraphRepository使用深度为4的T findOne(Long var1, int var2)来获得一个综合的课程对象。我担心我的知识这是一个非常罕见的深度。但是,在运行该方法时,它返回时没有任何明显的延迟。

问题 在进行一些压力测试时,我将数据库中的课程数量增加到4000,并发现延迟呈指数增长。向后工作深度2最多20秒,3次约60秒,4次从未返回超过5分钟。尽管如此,所有3个先前都以毫秒为单位返回。

我发现这很奇怪,因为我正在构建单个课程节点(由长节点ID标识),因此增加的课程数量不应该以这种方式改变findOne方法的速度。它仍然会构建相同大小的对象。

测试 为了测试替代方案,我运行MATCH (course:Course{courseCode:'HG65'})-[*1..4]->(x)RETURN *以查看需要多长时间(此处课程代码将查询限制为一个课程节点而不是节点ID)。它立即恢复了我想要的东西:

enter image description here

这让我觉得它可能与结果映射到GraphRepository中的POJO有关。为了测试我创建了一些映射函数,用于获取Neo4jOperation Result对象并通过解析+实例化/填充我的Course对象迭代结果图。在这个意义上,我将模仿深度为4的findOne。这没有延迟。 我唯一想到的是,findOne忽略了导致“course1 - &gt; school - &gt; course2”的关系方向,导致大量增加。虽然我现在不知道如何确认这种情况,也不知道如何绕过它。

问题

为什么当我添加更多课程对象时,findOne(ID,4)运行得如此之慢?每次我想要获取复杂的POJO时,如何在不编写定制查询和结果映射器的情况下克服此问题。

我应该采取其他方法吗?

1 个答案:

答案 0 :(得分:0)

在检查了我的spring项目到Neo4j数据库的调用后,我确认了问题。 findOne()使用(n)-[]-(m)关系。确切的查询如下:

MATCH (n) WITH n.nodeId = {id} MATCH p=(n)-[*0..4]- (m) RETURN p

这就是我的预期。如果我有10000个课程,这些课程都与一个深度的单个节点相关,那么它们将以2个深度相互匹配。 course -[]- school -[]- course。这意味着任何其他与课程相关的查询都会以指数方式增加。

我的解决方案是更改默认查询并将其作为GraphRepository查询,如下所示:

MATCH (n:Course{courseCode:{courseCode}}) WITH n MATCH p=(n)-[*0..4]->(m) RETURN p

请注意,该关系已从双向更改为-[]->向外方向。此解决方案与sping映射OGM完美配合,并且复杂POJO中的所有子类都按预期填充。