Neo4j двунаправленный обход API

1

Я играю с Neo4j, и до сих пор у меня есть географический график, где AIRPORT соединяется с CITY, CITY COUNTRY и COUNTRY с CONTINENT, как показано на рисунке Изображение 174551

Ярлыки на стрелках переводят в org.neo4j.graphdb.RelationshipType в мой код. Пока я могу построить путь между стартовым узлом MXP до конечного узла LTN используя следующий однонаправленный обход.

Traverser traverse = database.traversalDescription().depthFirst()
  .relationships(CITY, BOTH)
  .relationships(CONTINENT, BOTH)
  .relationships(COUNTRY, BOTH)
  .relationships(REGION, BOTH)
  .evaluator(Evaluators.includeWhereEndNodeIs(endNode)).traverse(startNode);

С этим я получаю единственный путь MXP → Milan → Italy → Europe <- England <- London <- LTN, что верно, учитывая описание графика, описание обхода и, конечно, мое понимание моего понимания такого описания.

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

TraversalDescription startSide = database.traversalDescription().depthFirst() //Depth first algorithm
  .relationships(CITY, OUTGOING) //consider CITY relationship, only outgoing
  .relationships(REGION, OUTGOING) //consider REGION relationship, only outgoing
  .relationships(COUNTRY, OUTGOING) //consider COUNTRY relationship, only outgoing
  .relationships(CONTINENT, OUTGOING) //consider CONTINENT relationship, only outgoing
  .evaluator(Evaluators.excludeStartPosition()); //do not consider the starting point. 
                                               //Here I tried also with all, with the same result
                                               //with includeWhereEndNodeIs(endNode), again with same result
                                               //and combining includeWhereEndNodeIs and excludeStartPosition, once more with same result.
                                               //All tries I mirrored for the endSide description, changing endNode to startNode where I feel it was needed

TraversalDescription endSide = database.traversalDescription().depthFirst()
  .relationships(CITY, OUTGOING)
  .relationships(REGION, OUTGOING)
  .relationships(COUNTRY, OUTGOING)
  .relationships(CONTINENT, OUTGOING)
  .evaluator(Evaluators.excludeStartPosition());

List<Node> asList = Arrays.asList(startNode, endNode);
Traverser traverse = database.bidirectionalTraversalDescription().endSide(endSide).startSide(startSide).traverse(asList, asList);

Здесь вместо пути, который я получаю с попыткой однонаправленного обхода, я получаю два пути: один только с MXP и один с LTN.

В этот момент я всерьез полагаю, что полностью недопонимаю двунаправленный обход и, возможно, даже его цель. Где моя ошибка? Почему я не получаю такой же результат?

  • 0
    Может быть, изучение через тесты github.com/neo4j/neo4j/blob/master/community/kernel/src/test/… помогает получить больше понимания.
  • 0
    Я уже нашел их, но не нашел времени, чтобы прочитать их полностью. Теперь я потратил эти 50 минут, чтобы прочитать их, и они хорошо написаны и понятны. Я до сих пор не решил свою проблему, но я думаю, что смогу, пройдя еще глубже. Спасибо @StefanArmbruster!
Теги:
neo4j
graph-databases

1 ответ

0
Лучший ответ

Наконец-то я получил рабочее решение. Проблема в моем коде была связана с понятием уникальности. Интересные моменты для моей проблемы:

Устанавливает правила того, как позиции могут быть просмотрены во время обхода, как указано в Uniqueness. Значение по умолчанию, если не установлено, - NODE_GLOBAL.

Уникальность NODE_GLOBAL: ни один узел на всем графике не может быть посещен более одного раза. Это может потенциально потреблять много памяти, поскольку для этого требуется сохранить структуру данных в памяти, запоминающую все посещенные узлы.

Уникальность NODE_PATH: узел может не встречаться ранее в пути, достигающем его.

Эти описания каким-то образом отличаются от официального API, поэтому я играл в разные комбинации и получал следующий код:

TraversalDescription bothSide = database.traversalDescription().depthFirst()
    .relationships(CITY, OUTGOING)
    .relationships(REGION, OUTGOING)
    .relationships(COUNTRY, OUTGOING)
    .relationships(CONTINENT, OUTGOING)
    .uniqueness(NODE_PATH);

Traverser traverser = database
    .bidirectionalTraversalDescription()
    .startSide(bothSide)
    .endSide(bothSide)
    .traverse(node, endNode);

В принципе, я определил общее TraversalDescription как для конца, так и для начала, где я хочу следовать только отношениям OUTGOING, и я хочу рассматривать пути только там, где узлы уникальны внутри самого пути.

Затем я определил bidirectional traverser который просто устанавливает конец и стартовую сторону и пересекает график от узла начального node до конечного узла endNode (ну, фактически он проходит от начала до конца И от конца до начала в то же время и останавливается, когда сталкиваются два обхода, объединяя результирующие пути в один путь, ведущий от start до end).

ПРИМЕЧАНИЕ. Я не совсем уверен в значении NODE_GLOBAL, поскольку в моей базе данных каждый узел представляет собой географический объект, поэтому каждый узел на пути MXP → Milan → Italy → Europe <- England <- London <- LTN должен можно посещать только один раз, и поэтому в этом контексте не должно быть разницы между NODE_GLOBAL и NODE_PATH.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню