为什么 findOne(<id>, <depth>) 在添加更多相同标签的节点时性能会变得不可接受?

Why is findOne(<id>, <depth>) getting unacceptably slow performance when adding more nodes of the same label?

上下文

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

@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)。它立即返回正是我想要的:

这让我觉得这可能与 GraphRepository.To 测试中映射到 POJO 的结果有关 我创建了一些映射函数来获取 Neo4jOperation 结果对象和 instantiating/populating 我的课程通过解析 + 遍历 Results Map 来获取对象。从这个意义上说,我将模拟深度 4 的 findOne。这个 运行 没有延迟。 我对此唯一的想法是 findOne 忽略了导致 "course1 -> school -> course2" 事件大量增加的关系方向。虽然我现在不知道如何确认这种情况,也不知道如何绕过它。

问题

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

我应该采取其他方法吗?

检查从我的 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 中的所有子 类 都按预期填充。