Какой запрос Cypher для извлечения отношений определенных узлов друг с другом в Neo4J? - PullRequest
0 голосов
/ 01 января 2019

TL: DR:

Мне нужно найти наиболее эффективный запрос Cypher, который бы связывал узлы с определенным типом узлов с определенным типом отношений, а затем извлекатьсоединений между этими узлами, отфильтруйте 150 лучших из них и покажите их пользователю.

Я предлагаю один ниже, используя запрос свойства отношений APOC, но я думаю, что его можно сделать более эффективным, поэтому я жду вашего совета.

ДЛИННОЕ ОБЪЯСНЕНИЕ:

В моей модели данных у меня есть узлы типа:

:Concept :Context :User :Statement

Это используется для анализа текстовой сети, поэтомуосновная идея заключается в том, что :Concepts появляются в :Statements, которые принадлежат определенному :Context, добавленному определенным :User.

Они также имеют свойства, такие как uid (уникальный идентификатор) и name (название).

Каждый :Concept связан с любым другим :Concept с типом направленного отношения :TO.

Если :Concept принадлежит :Context, оно имеет отношение :AT к этому :Context

Если :Concept сделано с помощью :User, то оно подключеноэтому пользователю с отношением типа :BY.

Я также добавил свойства в отношения, чтобы они указывали, какой пользователь установил соединение :TO и в каком контексте он появился.

Мне нужно получить список узлов и их взаимосвязей в определенном контексте, поэтому в настоящее время я использую запрос Cypher / APOC типа:

CALL apoc.index.relationships('TO','user:15229100-b20e-11e3-80d3-6150cb20a1b9') 
YIELD rel, start, end 
WITH DISTINCT rel, start, end 
MATCH (ctx:Context) 
WHERE rel.context = ctx.uid 
AND (ctx.name="decon" ) 
RETURN DISTINCT start.uid AS source_id, 
start.name AS source_name, 
end.uid AS target_id, 
end.name AS target_name, 
rel.uid AS edge_id, 
ctx.name AS context_name, 
rel.statement AS statement_id, 
rel.weight AS weight 

Он работает довольно хорошо, однако проблема заключается в том, что еслиГрафик большой (например, более 1000 узлов и 5000 соединений), его запрос занимает слишком много времени.

Итак, я хочу иметь возможность фильтровать количество получаемых отношений.

Используя приведенный выше запрос, это довольно сложно сделать, так как я хочу отфильтровать 150 самых верхних подключенных узлов, и мне нужно сначала получить данные, чтобы сделать это.

ИтакЯ подумал, что, возможно, мне следует изменить логику своего запроса и вместо этого:

1) Запросить интересующий меня :Context 1062 *

2) Подключить все узлы :Conceptк этому;

3) Найти все отношения извлеченных :Concept узлов друг к другу;

4) Получить X (150) самых верхних :Concept соединенных узлов, не обращая внимания на остальные.

5) Покажите их пользователю.

Я попробовал следующий запрос:

MATCH (ctx:Context{name:'decon',by:'15229100-b20e-11e3-80d3-6150cb20a1b9'}) 
WITH ctx MATCH (c1:Concept)-[:AT]->(ctx),
(c2:Concept)-[:AT]->(ctx) 
WITH c1, c2 
MATCH (c1)-[rel:TO]->(c2) 
RETURN DISTINCT rel;

Но, похоже, это займет гораздо больше времени.

Мне также нужно отфильтровать отношения между этими узлами, чтобы они отображали только отношения, сделанные определенным :User и появляющиеся только в определенных :Statement.

У любого есть идея, что еще я мог бы попробовать?

PS Исходный код находится в https://github.com/noduslabs/infranodus/blob/master/lib/entry.js#L573

1 Ответ

0 голосов
/ 02 января 2019

Вы генерируете декартово произведение из этих: узлов концепции, которые замедляют ваш запрос.

Вместо этого вы можете попробовать это:

MATCH (c:Concept)-[:AT]->(:Context{name:'decon',by:'15229100-b20e-11e3-80d3-6150cb20a1b9'}) 
WHERE (c)-[:BY]->(:User {uid:'15229100-b20e-11e3-80d3-6150cb20a1b9'})
// AND <additional predicate for desired :Statement>
WITH collect(c) as concepts
UNWIND concepts as c
WITH c, size([(c)-[:TO]->(c2) WHERE c2 in concepts | c2]) as connections
ORDER BY connections DESC
LIMIT 150
RETURN c

Вы, конечно, захотитеindex on: Контекст (по), чтобы начальное совпадение было быстрым.

...