How to realize a nested tree in Neo4j?

痞子三分冷 提交于 2019-12-04 09:49:59

Well, because trees actually are graphs using a graph database to store a tree seems entirely appropriate to me. What will perform the best will depend on your data access patterns, but basically trees are just a specialization of graphs.

Yes, in your case the "elements in the tree" would be nodes, and the "nesting" would be relationships. So here's how you might mock up your example:

CREATE (root:Article {label: "Article"}),
       (c1:Comment {label: "Comment 1"}),
       (c1a:Comment {label: "Comment 2 on comment 1"}),
       (c1b:Comment {label: "Comment 3 on comment 1"}),
       (c1b1:Comment {label: "Comment 4 on comment 3"}),
       (c2:Comment {label: "Comment 5 on article"}),
       (root)<-[:reply]-(c1),
       (c1)<-[:reply]-(c1a),
       (c1)<-[:reply]-(c1b),
       (c1b)<-[:reply]-(c1b1),
       (root)<-[:reply]-(c2);

This just creates a bunch of nodes and relationships, mimicking the structure you provided. Here I've chosen to always use :reply to connect things.

Now, "getting everything" just means traversing all of the :reply relationships we created:

MATCH p=(a:Article {label: "Article"})<-[:reply*1..]-(otherThing) 
WITH nodes(p) as nodes
RETURN nodes[length(nodes)-2] as InResponseTo, 
       nodes[length(nodes)-1] as CommentOrReply;

What this query does is traverse any number of :reply links (starting from the root "Article"). Then it only looks at the nodes in that path, and returns the last item (CommentOrReply) and what it was in response to (the second last item).

The result looks like this:

+-------------------------------------------------------------------------------------+
| InResponseTo                             | CommentOrReply                           |
+-------------------------------------------------------------------------------------+
| Node[18]{label:"Article"}                | Node[19]{label:"Comment 1"}              |
| Node[19]{label:"Comment 1"}              | Node[20]{label:"Comment 2 on comment 1"} |
| Node[19]{label:"Comment 1"}              | Node[21]{label:"Comment 3 on comment 1"} |
| Node[21]{label:"Comment 3 on comment 1"} | Node[22]{label:"Comment 4 on comment 3"} |
| Node[18]{label:"Article"}                | Node[23]{label:"Comment 5 on article"}   |
+-------------------------------------------------------------------------------------+

So that's how you traverse an entire tree.

EDIT - for what it's worth, "variable length path matching", which in the query above was just this bit: <-[:reply*1..]- is for me one of the top 3 selling points for a graph database. It's precisely that which graph DBs make really easy, that most of your other alternatives like relational make into a tortuously painful exercise. So if you need to do that sort of thing (like here, assembling an entire tree) I would claim that argues for a graph DB because you're using it in its area of fundamental strength.

If the nested trees are entirely directed graphs and have no cycles (i.e., directed acyclical graph=DAG), then you might consider transitive closure methods in a relational database. These allow very quick queries thru multiple nesting levels & finds of multiple intersections. They have the n-squared issue, so there are lots of rows, but with bigint indexes the queries run fast.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!