#mysql #graph #neo4j #spark-graphx
#mysql #График #neo4j #spark-graphx
Вопрос:
У меня есть коллекция узлов, которые составляют DAG (ориентированный ациклический граф) без гарантированных циклов. Я хочу сохранить узлы в базе данных и заставить базу данных выполнить поиск, который покажет мне все пути между двумя узлами.
Например, вы можете подумать, что у меня есть история git сложного проекта.
Каждый узел может быть описан с помощью объекта JSON, который имеет:
{'id':'id',
'outbound':['id1','id2','id3']}
}
Итак, если бы у меня были эти узлы в базе данных:
{'id':'id0',
'outbound':['id1','id2']}
}
{'id':'id1',
'outbound':['id2','id3','id4','id5,'id6']}
}
{'id':'id2',
'outbound':['id2','id3'}
}
И если бы я хотел знать все пути, соединяющие id0
и id3
, я бы хотел получить три списка:
id0 -> id1 -> id3
id0 -> id2 -> id3
id0 -> id1 -> id2 -> id3
Сегодня у меня тысячи таких узлов, завтра у меня будут десятки тысяч. Однако в базе данных много баз данных, а типичная база данных DAG имеет только 5-10 узлов, поэтому эта проблема решаема.
Я считаю, что нет способа сделать это эффективно MySQL (прямо сейчас все объекты хранятся в таблице в столбце JSON), однако я считаю, что это можно эффективно сделать в базе данных graph, такой как Neo4j.
Я просмотрел документацию Neo4J по алгоритмам поиска путей и, возможно, я в замешательстве, но примеры на самом деле не похожи на рабочие примеры. Я нашел пример MySQL, который использует хранимые процедуры, и похоже, что он не очень хорошо распараллеливается. Я даже не уверен, что делает Amazon Neptune; Я думаю, что он использует Spark GraphX.
Я как бы не понимаю, с чего начать.
Комментарии:
1. Как вы думаете, почему найденные вами примеры на самом деле не выглядят как рабочие? Пожалуйста, поделитесь тем, что вы пробовали, потому что ваш случай кажется очень графичным.
Ответ №1:
Это вполне выполнимо с Neo4j.
Импорт данных json
[
{"id":"id0",
"outbound":["id1","id2"]
},
{"id":"id1",
"outbound":["id2","id3","id4","id5","id6"]
},
{"id":"id2",
"outbound":["id2","id3"]
}
]
CALL apoc.load.json("graph.json")
YIELD value
MERGE (n:Node {id: value.id})
WITH n, value.outbound AS outbound
UNWIND outbound AS o
MERGE (n2:Node {id: o})
MERGE (n)-[:Edge]->(n2)
По-видимому, предоставленные вами данные не являются ациклическими…
Получение всех путей между двумя узлами
Поскольку вы упоминаете не кратчайшие пути, а все пути, конкретного алгоритма не требуется:
MATCH p=(:Node {id: "id0"})-[:Edge*]->(:Node {id: "id3"}) RETURN nodes(p)
"[{""id"":id0},{""id"":id1},{""id"":id3}]"
"[{""id"":id0},{""id"":id2},{""id"":id3}]"
"[{""id"":id0},{""id"":id1},{""id"":id2},{""id"":id3}]"
"[{""id"":id0},{""id"":id2},{""id"":id2},{""id"":id3}]"
"[{""id"":id0},{""id"":id1},{""id"":id2},{""id"":id2},{""id"":id3}]"
Сравнение с MySQL
Посмотрите, насколько быстрее на самом деле является графическая база данных
Ответ №2:
Алгоритмы поиска путей в библиотеке Graph Data Science предназначены для поиска кратчайших взвешенных путей и используют алгоритмы, аналогичные Дейкстре, для их поиска. В вашем случае кажется, что вы имеете дело с направленным невзвешенным графом, и вы могли бы использовать встроенную allShortestPath
процедуру cypher:
Примером может быть:
MATCH (n1:Node{id:"A"}),(n2:Node{id:"B"})
MATCH path=allShortestPaths((n1)-[*..10]->(n2))
RETURN [n in nodes(path) | n.id] as outbound_nodes_id
Всегда полезно проверить Cypher refcard, чтобы увидеть, что доступно с Cypher в Neo4j