2011-11-02 34 views
18

导入的graph databases语言,理解在Rails中建模一个无向图?

  1. 节点由圆圈表示),
  2. 边缘由箭头表示),和
  3. 性质元数据节点/边缘

Graph Database Property Graph

图形(维基百科提供)描述了一种directed graph

在Rails中建模undirected graph的最佳方式是什么?

也就是说,一个图,其中所有边缘都倒数(如在上述图形),并且其中每个边缘的属性是相同的与方向无关(违背图形上文)。

让我们假设通过ActiveRecord使用SQL存储的默认Rails 3设置。

polymorphic association将创建一个有向图,能够模拟上述图像描述的数据。

def Edge < ActiveRecord::Base 
    belongs_to :head, polymorphic: true 
    belongs_to :tail, polymorphic: true 
end 

class Node < ActiveRecord::Base 
    has_many :from, as: :head 
    has_many :to, as: :tail 
end 

class Group < ActiveRecord::Base 
    # a Node of Type: Group 
    has_many :from, as: :head 
    has_many :to, as: :tail 
end 

应该扩展这个模型来管理逆关系还是更好的模型?一个应用程序的


一个元件可以是一个图的问题,但是这并不意味着该应用是解决该问题的中心,即图断面必须在数据来执行,也不是该数据集是大于可用内存。

+2

如果您需要使用大图的高性能,您需要处理您的假设。这对于(sql)RDBMS来说是不合适的。 –

+1

不适合大图吗?绝对。但尽管如此。在初始原型之后交换或修改存储层,一旦有人将要处理的真实数据的例子比我的书中初始增加的复杂性更好。 (调用Knuth“过早优化...”) –

+6

正确的工具和设计选择与过早优化不同。你知道如何很好地使用锤子,你可以用锤子来驱动螺丝钉,但这并不意味着它是最好的工具。此时切换到螺丝刀不是一个过早的优化。如果你打算认真对待这个项目,而不仅仅是一个玩具,那么像这样的考虑事先就是完全意义上的。如果这只是一个实验,看看关系数据库如何存储图表,那也没关系,但让我们将其添加到问题中,以便我们知道这是主要意图。 – ctcherry

回答

10

在无向图,你需要知道的唯一的事情,是一个节点是否连接到另一个节点。没有方向的东西。

简单的方法:

class Node 
    has_many :connected_nodes 
    has_many :nodes, :through => :connected_nodes 
end 

class ConnectedNode 
    belongs_to :node 
    belongs_to :connected_node, :class_name => 'Node' 
end 

这也被称为邻接表:对于每个节点,我们可以很容易地相邻(连接)的节点列表。

这种方法可能存在一个问题:我们将连接存储两次。 A连接到B并且B连接到A.

因此,似乎更好地将每个连接存储一次,然后我们非常接近您的原始提议。

class Connection 
    belongs_to :node1, :class_name => 'Node' 
    belongs_to :node2, :clasS_name => 'Node' 
end 

只有我们尽我们最大的努力不要通过命名强制任何命令或方向。

检索连接的节点是连接到node1node2的所有节点,因此有效地忽略任何可能的方向。

在这种情况下,您还需要表示验证与(node1,node2)的连接是唯一的,但(node2,node1)实际上是相同的,并且不能插入两次。

我个人的选择是使用第二种模式,但保持第一种解决方案可能会更快(另请参阅此question)。

我还发现了一个非常有趣的article,作者解释了图表如何存储在数据库中。非常深刻的,但更多的数据库为中心。

希望这会有所帮助。

+0

我同意我只想在数据库中存储连接/边缘,所以我更喜欢你的第二个例子。但是,在这个例子中,我的Node类将如何看待? 好像ActiveRecord的has_many关系总是定向的,不是吗? – NobodysNightmare

+0

node1.connections将产生节点2。但node2.connections不会产生任何东西。 @nathanvda –

+0

我没有说明如何实现它(但描述了它:查找所有连接为“node1”或“node2”的节点)。看来你只是寻找一种?请提出另一个问题,在那里你可以显示你的尝试和错误,并把链接放在这里,我会看看。 – nathanvda

3

而不是使用多态关联的,请尝试使用的has_many,:通过

class Group < ActiveRecord::Base 
    has_many :memberships 
    has_many :persons, :through => :memberships 
end 

class Membership < ActiveRecord::Base 
    belongs_to :group 
    belongs_to :person 
end 

class Person < ActiveRecord::Base 
    has_many :memberships 
    has_many :groups, :through => :memberships 
end 

您可以储存边缘的性能诠释的会员制模式。

+0

根据我的理解,通过has_many将创建一个有效的无向图,并在迁移过程中增加一个'add_index:memberships,[:group_id,:person_id],unique:true',代价是表蔓延。试图精确地为该图建模,在您的示例中需要一个额外的表来处理Person类上的自我指涉'知道'边缘。 –

2
+1

考虑[图数据库](http://en.wikipedia.org/wiki/Graph_database)是问题中的第一个链接,让我们假设人们已经阅读[both](http://stackoverflow.com/questions/3689182/ when-developing-web-applications-when-you-you-use-a-graph-database-versus-a-do)先前存在的[posts](http://stackoverflow.com/questions/5896288/rails-3-and - 图-数据库)。这个问题出现在我自己的原型中,当编写代码的第一行时,恕我直言分解图形数据库是矫枉过正的。如果你不同意,一个解释将*非常赞赏。 –

+0

我完全错过了'使用sql商店'的一点。 GDB是这些任务的很好解决方案,因为它们提供了良好的链接行走性能和查询。如果没有严重的负载或长链接漫游,连接表与其他字段也是一个很好的解决方案。 –

+0

对于一个小图,只要将其保存在内存中,并将其存储为blob(如果需要持久性)。对于大图,只需计算所需的磁盘访问次数。 RDBMS加入会降低性能。 –

相关问题