Зашифрованный запрос Neo4j отображает древовидный подграф, начиная с одного узла без определенной последовательности отношений и узлов (настолько эффективный, насколько это возможно)
Я хочу отобразить древовидный подграф, показывающий все пути, начиная с одного узла. Большинство соединений являются двунаправленными (в настоящее время 2 ребра, вероятно, изменяются на 1 ребро вместо этого для лучшей производительности), и у меня есть разные типы отношений. Но есть одна особая последовательность узлов и отношений, приводящая к еще большему количеству циклов, и эта последовательность не должна отображаться в результирующем графе.
MATCH p=(n)-[r*0..4]-(m) WHERE n.CAT='a1' RETURN p
Этот запрос почти решает проблему, но я не смог найти / создать правильный запрос, чтобы исключить последовательность из графика. Глубина все еще ограничена, потому что с глубиной [r*0..9]
Веб-приложение neo4j перестало отвечать (не главная проблема! Я уже знаю, как улучшить / исправить это), и потребовалось время, чтобы остановить базу данных. Последовательность создает самые нежелательные перестановки и тонны возможных путей и петель. Нет никакого способа изменить отношения (кроме использования 1 ребра вместо 2, практически двунаправленного, но насколько я знаю, операция должна быть такой же и менее сложной, исправьте меня, если я ошибаюсь) между узлами, потому что с другим начальным узлом связь потенциально необходима.
Последовательность:
(x)-[:relation2]-(y)-[:relation2]-(z)
а также x,y,z
все имеют одинаковое значение свойства в CAT='variable'
, Это всегда одинаковые отношения и одинаковые свойства. Значения и узлы различаются.
Все узлы являются потенциальными начальными узлами.
Кроме того, запрос должен быть очень-очень быстрым, имея дело с разделением длинных путей (разных длин). Большинство расщеплений будут игнорироваться с исключенной последовательностью. Глубина должна быть неограниченной. Результирующие пути всегда заканчиваются, как только запрос игнорирует последовательность и не "идет" по этому пути.
Чтобы избежать недоразумений:
Например, x,y,z1 и z3 имеют одно и то же свойство CAT(category)='a' и z2.CAT='b'.
display
не отображать и не останавливать
(x)-[:relation2]-(y)
- [: relation2] - (z1)
(x)-[:relation2]-(y)-[:relation2]-(z2)
(x)-[:relation2]-(y)-[:relation1]-(z3)
x.CAT = y.CAT = z1.CAT = z3.CAT! = z2.CAT
Выполнение запроса очень важно, и причина, по которой я это делаю, но сначала мне нужно "простое" решение для продвижения этого проекта.
Заранее большое спасибо.
2 ответа
Для этого вы должны создать собственный обход. Для этого в Neo4j есть API, посмотрите документацию: https://neo4j.com/docs/java-reference/current/
Чтобы не проходить дважды узел, вы должны использовать NODE_PATH как правило уникальности (в шифре это уникальность RELATIONSHIP_PATH, чтобы избежать цикла графа).
Как отметили @Tezra и @logisima, ключом является API обхода. Но это не сделано с уникальностью или чем-то таким сложным. Это наконец напечатало результаты, которые я искал:
TraversalDescription td = graphDb.traversalDescription()
.depthFirst()
.uniqueness(Uniqueness.RELATIONSHIP_GLOBAL)
.evaluator( new Evaluator()
{
@Override
public Evaluation evaluate( final Path path )
{
Node parent=null,grandParent =null;
Relationship rel1=null,rel2=null;
int nCount=0,rCount=0;
if(path.length()>=2)
{
for(Node node : path.reverseNodes())
{
if(nCount==1)
parent = node;
if(nCount==2)
grandParent=node;
if(nCount>2)
break;
nCount++;
}
for(Relationship rel : path.reverseRelationships())
{
if(rCount==0)
rel1 = rel;
if(rCount==1)
rel2=rel;
if(rCount>1)
break;
rCount++;
}
}
if(path.length()<2)
{
return Evaluation.INCLUDE_AND_CONTINUE;
}
else if (path.length()>=2
&& rel1.isType(relType)
&& rel2.isType(relType)
&& path.endNode().getProperty("CATEGORY").toString().equals(parent.getProperty("CATEGORY").toString())
&& path.endNode().getProperty("CATEGORY").toString().equals(grandParent.getProperty("CATEGORY").toString()))
{
return Evaluation.EXCLUDE_AND_PRUNE;
}
else
{
return Evaluation.INCLUDE_AND_CONTINUE;
}
}
});
try ( Transaction tx = graphDb.beginTx() )
{
Traverser traverser = td.traverse(graphDb.getNodeById(id));
for ( Path path : traverser)
{
System.out.println(path.toString());
}
tx.success();
}
(особая благодарность @Tezra за то, что вовремя попала на правильный путь)
Решение с помощью apoc также должно быть возможным, а также избежать проблемы возврата графа в neo4j.
Для этого вы должны создать собственный обход. Для этого в Neo4j есть API, посмотрите документацию: https://neo4j.com/docs/java-reference/current/
Чтобы не проходить дважды узел, вы должны использовать NODE_PATH
как правило уникальности (в Cypher, это RELATIONSHIP_PATH
уникальность, чтобы избежать цикла графа).
ура