2016-04-07 1 views
0

КОНТЕКСТПочему findOne (<id>, <depth>) получает неприемлемо низкую производительность при добавлении большего количества узлов одной метки?

Я разработки веб-сайта пружинный загрузочный подкрепленную базу данных Neo4j. Он предназначен для работы в качестве системы поиска университетских курсов. (Соответствующая структура является то, что курсы имеют modulesets, которые имеют модули, которые имеют отношение к предметам, и т.д ...)

@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; 

Для курса страниц мне нужно заполнить все сложные полей, конечно, чтобы они могли отображаться на странице. Я использовал T findOne(Long var1, int var2) с глубиной 4 через GraphRepository, чтобы получить комплексный объект курса. Я был обеспокоен, насколько мне известно, это очень необычная глубина. Однако при запуске метода он возвращался без какой-либо заметной задержки.

ПРОБЛЕМА При выполнении какого-то стресс-тестирования, я увеличил количество курсов в базе данных 4000 и обнаружил увеличение задержки в геометрической прогрессии. Рабочая обратная глубина 2 составляла до 20 секунд, 3 - около 60 секунд, а 4 никогда не возвращались в течение 5 минут. Это несмотря на то, что все три ранее возвращались в миллисекундах.

Я нашел это нечетным, поскольку я строил отдельный узел курса (идентифицированный длинным идентификатором узла), поэтому увеличенное количество курсов не должно было изменять скорость метода findOne таким образом. Он все равно будет строить объект того же размера.

ТЕСТИРОВАНИЕ Чтобы проверить альтернативы я побежал MATCH (course:Course{courseCode:'HG65'})-[*1..4]->(x)RETURN *, чтобы увидеть, сколько времени это займет (OBV здесь конечно код ограничивает запрос к одному узлу курса вместо идентификатора узла). Он вернулся сразу именно то, что я хотел:

enter image description here

Это заставило меня думать, что это может быть что-то делать с отображением результата на POJO в тесте GraphRepository.To этого я создал несколько функций отображения для принятия Объект Результат Neo4jOperation и создание/заполнение объекта курса путем разбора + итерации по Карте результатов. В этом смысле я буду эмулировать findOne глубины 4. Это продолжалось без задержки. Моя единственная мысль об этом заключается в том, что findOne игнорирует направления отношений, ведущие к «курсу 1 -> школа -> курс2», что приводит к массовому увеличению выборки. Хотя я не знаю, как это подтвердить, и как обойти это.

ВОПРОС

Почему findOne (ID, 4) работает так медленно, когда я добавляю больше объектов курса? Как я могу преодолеть эту проблему, не набирая на заказ запросы и получатели результатов каждый раз, когда я хочу получить сложный POJO.

Есть ли альтернативный подход, который я должен принять?

+0

У вас есть набор данных/код, который мы могли бы использовать для проверки этого? Пожалуйста, откройте проблему на https://jira.spring.io/browse/DATAGRAPH с любыми данными, которые вы можете предоставить – Luanne

ответ

0

После проверки звонков из моего проекта весны в базу данных 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 заполняются, как ожидалось.