2011-09-24 162 views
18

我有一个关于在图形数据库中建模的一般问题,我似乎无法将我的头围绕。如何在图形数据库中建立真实世界的关系(如Neo4j)?

你如何塑造这种类型的关系:“牛顿发明微积分”?

simple graph,你可以喜欢这个型号:

Newton (node) -> invented (relationship) -> Calculus (node) 

...所以你有一堆,你增加了更多的人,发明的“发明”曲线关系。

的问题是,你开始需要一堆属性添加到关系:

  • invention_date
  • influential_concepts
  • influential_people
  • books_inventor_wrote

...和您需要开始在这些属性和其他节点之间创建关系,如:

  • influential_people:对人的关系节点
  • books_inventor_wrote:关系到预定节点

所以现在看起来像“真实世界的关系”(“发明”)实际上应该是一个节点图形,图形应该是这样的:

Newton (node) -> (relationship) -> Invention of Calculus (node) -> (relationship) -> Calculus (node) 

而对于复杂的事情更多,其他人也参加微积分的发明,使图表现在变成这样的:

Newton (node) -> 
    (relationship) -> 
    Newton's Calculus Invention (node) -> 
     (relationship) -> 
     Invention of Calculus (node) -> 
      (relationship) -> 
      Calculus (node) 
Leibniz (node) -> 
    (relationship) -> 
    Leibniz's Calculus Invention (node) -> 
     (relationship) -> 
     Invention of Calculus (node) -> 
      (relationship) -> 
      Calculus (node) 

所以我问这个问题,因为它看起来像你不想实际的图形数据库上设置属性“的关系”对象,因为你可能想在某个点将它们视为图中的节点。

这是正确的吗?

我一直在研究Freebase Metaweb Architecture,他们似乎把所有东西当作一个节点。例如,Freebase的想法是Mediator/CVT,您可以在其中创建一个将“Actor”节点链接到“Film”节点的“Performance”节点,如下所示:http://www.freebase.com/edit/topic/en/the_last_samurai。不太确定这是否是同一个问题。

你有什么指导原则可以用来确定“现实世界关系”是否应该实际上是一个图节点而不是一个图关系?

如果有关于这个话题的好书,我很想知道。谢谢!

回答

18

其中一些东西,如invention_date,可以存储为边上的属性,就像在大多数图形数据库中一样,边可以具有与顶点可以具有属性相同的属性。例如,你可以做这样的事情(代码如下TinkerPop's Blueprints):

Graph graph = new Neo4jGraph("/tmp/my_graph"); 
Vertex newton = graph.addVertex(null); 
newton.setProperty("given_name", "Isaac"); 
newton.setProperty("surname", "Newton"); 
newton.setProperty("birth_year", 1643); // use Gregorian dates... 
newton.setProperty("type", "PERSON"); 

Vertex calculus = graph.addVertex(null); 
calculus.setProperty("type", "KNOWLEDGE"); 

Edge newton_calculus = graph.addEdge(null, newton, calculus, "DISCOVERED"); 
newton_calculus.setProperty("year", 1666); 

现在,让我们展开它一点点,并添加Liebniz:

Vertex liebniz = graph.addVertex(null); 
liebniz.setProperty("given_name", "Gottfried"); 
liebniz.setProperty("surnam", "Liebniz"); 
liebniz.setProperty("birth_year", "1646"); 
liebniz.setProperty("type", "PERSON"); 

Edge liebniz_calculus = graph.addEdge(null, liebniz, calculus, "DISCOVERED"); 
liebniz_calculus.setProperty("year", 1674); 

添加在书:

Vertex principia = graph.addVertex(null); 
principia.setProperty("title", "Philosophiæ Naturalis Principia Mathematica"); 
principia.setProperty("year_first_published", 1687); 
Edge newton_principia = graph.addEdge(null, newton, principia, "AUTHOR"); 
Edge principia_calculus = graph.addEdge(null, principia, calculus, "SUBJECT"); 

要找出牛顿在他发现的东西上写的所有书籍,我们可以构造一个图遍历。我们从牛顿开始,遵循他发现的事物的链接,然后反向链接获取有关该主题的书籍,并再次通过链接反向获取作者。如果作者是牛顿,那么回到书中并返回结果。该查询是写在Gremlin,为图遍历一个基于Groovy领域特定语言:

newton.out("DISCOVERED").in("SUBJECT").as("book").in("AUTHOR").filter{it == newton}.back("book").title.unique() 

因此,我希望我已经证明了一点聪明的遍历如何使用,以避免产生中间节点代表问题边缘。在一个小型的数据库中它并不重要,但是在一个大型数据库中,你将会遇到大量的性能问题。

是的,很遗憾,您不能将边与图中的其他边相关联,但这是这些数据库的数据结构的限制。有时将所有内容都作为节点是有意义的,例如,在Mediator/CVT中,性能也具有更具体一些。个人可能只希望在评论中提到汤姆克鲁斯在“最后的武士”中的表现。但是,对于大多数图形数据库,我发现某些图遍历的应用可以让我从数据库中获得我想要的内容。

+0

优秀的答案!这真的为我清除了一切,谢谢。 –