20

我有一个关于在图形数据库中建模的一般性问题,我似乎无法理解。

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

在一个简单的 graph 中,你可以这样建模:

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

...因此,当您添加更多人和发明时,您将拥有一堆“发明”的图形关系。

问题是,您开始需要向关系中添加一堆属性:

  • 发明日期
  • 有影响力的概念
  • 有影响力的人
  • books_inventor_write

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

  • 影响人:与人节点的关系
  • 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的想法,您可以在其中创建一个“Performance”节点,将“Actor”节点链接到“Film”节点,如下所示:http ://www.freebase.com/edit /topic/en/the_last_samurai。不太确定这是否是同一个问题。

您使用哪些指导原则来确定“现实世界的关系”是否实际上应该是图节点而不是图关系?

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

4

1 回答 1

19

其中一些东西,例如invention_date,可以存储为边上的属性,因为在大多数图形数据库中,边可以具有属性,就像顶点可以具有属性一样。例如,您可以执行以下操作(代码遵循TinkerPop 的蓝图):

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 编写的,Gremlin是一种基于 Groovy 的用于图遍历的领域特定语言:

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

因此,我希望我已经展示了如何使用巧妙的遍历来避免创建中间节点来表示边的问题。在小型数据库中这无关紧要,但在大型数据库中,您将遭受巨大的性能损失。

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

于 2011-09-24T11:28:56.853 回答