网络版本
最近,Ian Robinson 发表了一篇关于网络版本控制的不错的博文(点击此处阅读),介绍了如何使用身份节点和将结构与状态分离。在本篇 gist 中,我想通过引入另一种使用关系节点的方法来发表我的看法。这更多地是关于网络的结构,而不是节点的状态,但它以不同的方式处理版本控制。正如 Ian 在他的博文中所说,总需要权衡取舍,因为版本控制会增加存储和处理的额外负担。
关系节点?
什么是关系节点?
关系节点是两个网络节点之间的中间节点,表示节点之间的关系。
因此,如果 A 和 B 是两个网络节点,而不是使用[:RELTYPE]
关系连接它们,则会在两者之间插入一个关系节点,并使用[:RS]
和[RE]
连接它,分别代表关系开始和关系结束。

为什么要使用关系节点?
Neo4j(我首选的图数据库)当前 2.0.3 版本不允许在关系和节点之间创建关系。而如果我想表明两个网络节点之间的特定关系属于一个特定的网络(本身由一个节点表示),则需要这样做。
此外,我的用例要求我在网络之间共享网络节点,但在不同的结构中。
另一个原因是网络由节点之间的关系决定,而不是节点本身。如果我有两个节点 A 和 B,这并不能告诉我它们之间关系的信息,例如方向、类型或连接它们的多个关系。另一方面,如果我了解一个关系,我就会知道它的起始/结束节点及其类型。一个节点可以没有关系存在,而一个关系只能与起始和结束节点一起存在。
使用此方法的第四个原因是它允许我比较网络,例如回答“网络 1 的版本 3 能否与网络 2 的版本 1 共存?”之类的问题。但是,这不会是本篇 gist 的主题,因为它需要一些额外的思考时间。
创建网络
设置
创建网络的过程包括以下步骤:
-
创建一个表示网络的节点。
-
创建网络节点。
-
创建通过
[:RS]
和[:RE]
关系链接到网络节点的关系节点,并使用[:UPDATE {type:'ADD', version:1]
链接到网络节点。
设置查询创建了网络 1 的第一个版本,将 A 链到 B 再到 C。请注意,[:UPDATE]
关系的version
属性可以简单地替换或添加时间戳属性,使图感知时间。
CREATE (_0:`nw` {`name`:"Network1"})
CREATE (_5:`nwnode` {`name`:"A"})
CREATE (_6:`nwnode` {`name`:"B"})
CREATE (_7:`nwnode` {`name`:"C"})
CREATE (_13:`relationnode` {`id`:1})
CREATE (_14:`relationnode` {`id`:2})
CREATE _5-[:`RS`]->_13
CREATE _6-[:`RS`]->_14
CREATE _13-[:`RE`]->_6
CREATE _14-[:`RE`]->_7
CREATE _0-[:`UPDATE` {`type`:"ADD", `version`:1}]->_14
CREATE _0-[:`UPDATE` {`type`:"ADD", `version`:1}]->_13
此网络中的关系为:
MATCH (s:nwnode)-[:RS]->(rn:relationnode)-[:RE]->(e:nwnode)
RETURN s.name as From,e.name as To ORDER BY From,To
向网络添加节点
如果必须向网络添加节点,我们需要:
-
创建新节点。
-
创建一个关系节点。
-
创建一个
[:UPDATE]
,这次版本为:2。
MATCH (nw:nw {name:"Network1"}),(sn:nwnode {name:"C"})
CREATE (_8:`nwnode` {`name`:"D"})
CREATE (_15:`relationnode` {`id`:3})
CREATE (sn)-[:`RS`]->_15-[:`RE`]->_8
CREATE (nw)-[:`UPDATE` {`type`:"ADD", `version`:2}]->_15
我们网络的版本 2 中的关系为:
MATCH (s:nwnode)-[:RS]->(rn:relationnode)-[:RE]->(e:nwnode)
RETURN s.name as From,e.name as To ORDER BY From,To
从网络中移除节点
如果必须从网络中移除节点,我们需要做的是向相关的关系节点添加[:UPDATE {type:'REMOVE', version:3}]
关系。因此,完全从网络 1 中移除节点“C”只需:
-
查找连接“C”与网络 1 的关系节点。
-
在网络 1 和这些关系节点之间创建
[:UPDATE {type:'REMOVE', version:3}]
关系。
MATCH (nw:nw {name:"Network1"})-[:UPDATE]->(rn:relationnode)-[:RS|RE]-(n:nwnode {name:"C"})
WITH nw,COLLECT(DISTINCT rn) AS rns
FOREACH ( i IN rns |
CREATE (nw)-[:`UPDATE` {`type`:"REMOVE", `version`:3}]->(i)
)
此查询给出了现在存在的关系的完整列表:
MATCH (nw:nw {name:"Network1"})-[u:UPDATE]->(rn:relationnode),(s:nwnode)-[:RS]->(rn)-[:RE]->(e:nwnode)
RETURN u.version AS Version,u.type AS UpdateType,s.name AS From, e.name AS To
ORDER BY Version,UpdateType,From
为了获取我们网络的版本 3 中的关系,我们必须将搜索限制在网络范围内,并且只考虑类型为“ADD”的最新[:UPDATE]
事务。
您可以看到,通过移除 C,我们也把 D 从网络中切断了。太糟糕了,但幸运的是,我们也可以在现有节点之间创建关系。
历史版本
可以通过仅考虑[:UPDATE]
关系直到该版本来检索网络的特定版本。
网络 1 的版本 1
以及作为图形(仅在您访问此处时有效,即 2014 年 5 月 14 日 https://jexp.github.io/graphgist/?40364ac2a52f57aa520a。感谢 @Jim_Salmons 指出)。
添加第二个网络
使用此方法的原因之一是我需要能够在第二个网络中重用网络节点,并使用其自己的关系。
让我们创建一个具有 2 个版本的网络 2。
-
版本 1
-
C 到 A
-
-
版本 2
-
A 到 D
-
B 到 A
-
D 到 E
-
E 到 A
-
E 到 B
-
MATCH (na:nwnode {name:"A"}),(nb:nwnode {name:"B"}),(nc:nwnode {name:"C"}),(nd:nwnode {name:"D"})
CREATE (nw:`nw` {`name`:"Network2"})
CREATE (ne:`nwnode` {`name`:"E"})
CREATE (nc)-[:`RS`]->(rn1:relationnode)-[:`RE`]->(na)
CREATE (nw)-[:`UPDATE` {`type`:"ADD", `version`:1}]->(rn1)
CREATE (nw)-[:`UPDATE` {`type`:"REMOVE", `version`:2}]->(rn1)
CREATE (nb)-[:`RS`]->(rn2:relationnode)-[:`RE`]->(na)
CREATE (nw)-[:`UPDATE` {`type`:"ADD", `version`:2}]->(rn2)
CREATE (na)-[:`RS`]->(rn3:relationnode)-[:`RE`]->(nd)
CREATE (nw)-[:`UPDATE` {`type`:"ADD", `version`:2}]->(rn3)
CREATE (nd)-[:`RS`]->(rn4:relationnode)-[:`RE`]->(ne)
CREATE (nw)-[:`UPDATE` {`type`:"ADD", `version`:2}]->(rn4)
CREATE (ne)-[:`RS`]->(rn5:relationnode)-[:`RE`]->(nb)
CREATE (nw)-[:`UPDATE` {`type`:"ADD", `version`:2}]->(rn5)
CREATE (ne)-[:`RS`]->(rn6:relationnode)-[:`RE`]->(na)
CREATE (nw)-[:`UPDATE` {`type`:"ADD", `version`:2}]->(rn6)
之后,当前网络 2 的关系为:
后续思考
这是我的第一个 gist。设置起来很有趣。如果能有 //graph 东西可以可视化查询结果,而不是整个图形,那就太好了。更新:我们在 https://jexp.github.io/graphgist/?40364ac2a52f57aa520a 上有了 :),并且我想在不久的将来也会在 https://gist.neo4j.org/ 上有。
我更喜欢尽可能以图形的方式做事。不确定我是否在这方面取得了成功,但我试图记住,打开和关闭节点和关系而不是进行遍历是有代价的。
向[:UPDATE]
关系添加另一个属性{status: "pending"}
将允许我运行 Cypher 来回答诸如:“如果我这样做会怎样?”之类的问题。
正如我之前所说,向[:UPDATE]
关系添加时间戳将使其感知时间。您还可以创建版本节点的链接列表并将[:UPDATE]
链接到这些节点。
比较不同的网络将是我的下一个 gist 的内容。
我还将处理使用关系节点的可视化方面。有时您希望看到它们,有时它们会妨碍您,因为力导向布局可能会导致您不希望出现的角度。幸运的是,Cypher 允许您以可视化引擎可以处理的方式调整结果,并欺骗可视化引擎使其认为您提供给它的内容是关系。
感兴趣吗?在 @tomzeppenfeldt / @ophileon 上关注我。当然也欢迎任何评论。
此页面是否有帮助?