我刚刚开始使用 neo4j,并且我了解图形和关系的原理,但是对于我想要建模的某些结构,我遇到了一些麻烦。我想在编程语言项目中使用它,并存储已解析源文件的 AST。从那里开始,我计划向节点添加大量额外的数据和关系以帮助分析和工具,但基本的 AST 仍然有点困难。
制作树的天真方法是简单地遍历 AST 并将树中的每个节点复制到 neo4j 中的节点,使用属性来跟踪令牌数据等,然后使用 CHILD 关系指向子节点. 问题是,当我以后想要遍历树时,我需要能够以原始 AST 的正确顺序进行,但开箱即用我不太确定最好的方法。
我想到了两种基本方法。一种是只为每个 CHILD 关系添加一个索引/序数属性。另一种是与第一个孩子建立 FIRST 关系,在每个孩子之间建立 NEXT 关系以维持秩序。
对于这两种方法中的任何一种,似乎仍然没有任何开箱即用的东西可以用来以正确的顺序遍历它。我认为如果我执行 FIRST/NEXT,只要我强制 neo4j 始终先遍历 FIRST 并进行深度优先搜索,我就可以获得正确的顺序。那行得通吗?有没有更好的办法?这似乎是开箱即用的事情。
更新
最终我决定使用我的两个想法。子节点与索引属性具有 CHILD 关系。第一个孩子也有 FIRST_CHILD 关系。兄弟节点具有 NEXT_SIBLING 关系以给出正确的排序。之后,遍历就很简单了:
//reusable traversal description
final private TraversalDescription AST_TRAVERSAL = Traversal.description()
.depthFirst()
.expand(new OrderedByTypeExpander()
.add(RelType.FIRST_CHILD, Direction.OUTGOING)
.add(RelType.NEXT_SIBLING, Direction.OUTGOING));
然后当我真的需要走树的时候,我可以做
for(Path path : AST_TRAVERSAL.traverse(astRoot)){
//do stuff here
}
对于我的用例,我实际上并没有在创建后修改树结构本身——我只是执行分析并添加更多的关系和属性,所以这很容易维护。如果我必须做更多的修改,可能会做一些工作,特别是如果我想维护子关系的索引号。因此,对于处于类似情况的其他人来说,这可能是需要考虑的事情。
如果我确实遇到了更易变的东西,我可能会尝试 Peter Neubauer 建议的集合,并且可能只是创建一个 OrderedTreeNode 类,指向一个节点并为子级使用 List 集合。