Зашифрованный запрос 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 уникальность, чтобы избежать цикла графа).

ура

Другие вопросы по тегам