在Rails中建模无向图?

时间:2011-11-02 05:45:46

标签: ruby-on-rails activerecord graph polymorphism prototyping

导入graph databases的语言,了解

  1. 节点由圈子表示),
  2. 边缘由箭头表示)和
  3. 属性节点/边缘的元数据
  4. 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
    

    是否应该扩展此模型以管理反向关系,或者是更好的模型?


    应用程序的一个元素可能是图形问题,但并不意味着应用程序以问题为中心,必须对数据执行图表横向,数据集也不大于可用内存。

3 个答案:

答案 0 :(得分:12)

在无向图中,您唯一需要知道的是节点是否连接到另一个节点。而且没有方向这样的东西。

简单方法:

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,其中作者解释了图表如何存储在数据库中。非常深刻,但更加以数据库为中心。

希望这有帮助。

答案 1 :(得分:3)

尝试使用has_many,:through

,而不是使用多态关联
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

您可以在成员资格模型中存储边缘的属性。

答案 2 :(得分:2)