Оптимизация запросов Neo4j Cypher - ручной указатель APOC по свойствам отношений
В соответствии с логикой приложения я реализовал собственный построитель запросов Cypher, который создает сложные запросы на основе пользовательского ввода из пользовательского интерфейса.
Вот пример таких запросов:
MATCH (dg:DecisionGroup)-[:CONTAINS]->(childD:Decision)
WHERE dg.id = {decisionGroupId}
MATCH (childD)-[relationshipValueRel2:HAS_VALUE_ON]-(filterCharacteristic2:Characteristic)
WHERE filterCharacteristic2.id = 2
WITH relationshipValueRel2, childD, dg
WHERE (ANY (id IN {relationshipValueRel21} WHERE id IN relationshipValueRel2.value )) AND ( relationshipValueRel2.`property.1.3` = {property2} ) OR ( relationshipValueRel2.`property.1.3` = {property3} )
WITH childD, dg
MATCH (childD)-[relationshipValueRel3:HAS_VALUE_ON]-(filterCharacteristic3:Characteristic)
WHERE filterCharacteristic3.id = 3
WITH relationshipValueRel3, childD, dg
WHERE (relationshipValueRel3.`value` = 'London')
WITH childD , dg
SKIP 0 LIMIT 100
WITH *
MATCH (childD)-[ru:CREATED_BY]->(u:User)
OPTIONAL MATCH (childD)-[rup:UPDATED_BY]->(up:User)
RETURN ru, u, rup, up, childD AS decision,
[ (dg)<-[:DEFINED_BY]-(entityGroup)-[:CONTAINS]->(entity)<-[:COMMENTED_ON]-(comg:CommentGroup)-[:COMMENTED_FOR]->(childD)
| {entityId: toInt(entity.id), types: labels(entity), totalComments: toInt(comg.totalComments)} ] AS commentGroups,
[ (c1)<-[vg1:HAS_VOTE_ON]-(childD)
| {criterionId: toInt(c1.id), weight: vg1.avgVotesWeight, totalVotes: toInt(vg1.totalVotes)} ] AS weightedCriteria,
[ (dg)<-[:DEFINED_BY]-(chg:CharacteristicGroup)-[rchgch1:CONTAINS]->(ch1:Characteristic)<-[v1:HAS_VALUE_ON]-(childD)
| {characteristicId: toInt(ch1.id), v1:v1, optionIds: v1.optionIds, valueIds: v1.valueIds, value: v1.value, available: v1.available, totalHistoryValues: v1.totalHistoryValues, totalFlags: v1.totalFlags, description: v1.description, valueType: ch1.valueType, visualMode: ch1.visualMode} ] AS valuedCharacteristics
С небольшим количеством child:Decision
(например, < 1000) он работает довольно быстро, но производительность заметно снижается после увеличения объема данных.
Основной причиной этого являются операции фильтрации, основанные на свойствах отношения, таких как:
WHERE (ANY (id IN {relationshipValueRel21}
WHERE id IN relationshipValueRel2.value ))
AND ( relationshipValueRel2.`property.1.3` = {property2} )
OR ( relationshipValueRel2.`property.1.3` = {property3} )
Обратите внимание, что это только частный случай, и запрос, основанный на пользовательском вводе, может содержать десятки таких условий с (<, <=, =, >, >=, IN, ALL IN, ANY IN
) операции, в которых значением свойства может быть одно значение или массив.
Сейчас я думаю о том, как улучшить производительность этого запроса, потому что ожидаю десятки или сотни тысяч child:Decision
там. Для того, чтобы сделать это, я изучаю Индекс Руководства APOC по свойствам отношений
Принимая это во внимание - имеет ли смысл переопределить мой построитель запросов, чтобы использовать ручной указатель APOC для свойств отношений для упомянутой операции фильтрации, или это не поможет?