我需要在Ruby on Rails中实现无向图G =(V,E)并考虑构建 Vertex 和 Edge 模型,其中 Vertex has_many Edges 。
由于边缘恰好连接了两个顶点,您将如何在Rails中强制执行此操作?
你知道任何有助于实现这种图形的宝石或图书馆(对重新发明轮子不感兴趣; - ))?
答案 0 :(得分:9)
不知道在ActiveRecord之上提供图形逻辑的任何现有库。
您可能必须实现自己的Vertex,Edge ActiveRecord支持的模型(请参阅Rails安装的vertex.rb
目录中的edge.rb
和rails/activerecord/test/fixtures
),例如
### From Rails: ###
# This class models an edge in a directed graph.
class Edge < ActiveRecord::Base
belongs_to :source, :class_name => 'Vertex', :foreign_key => 'source_id'
belongs_to :sink, :class_name => 'Vertex', :foreign_key => 'sink_id'
end
# This class models a vertex in a directed graph.
class Vertex < ActiveRecord::Base
has_many :sink_edges, :class_name => 'Edge', :foreign_key => 'source_id'
has_many :sinks, :through => :sink_edges
has_and_belongs_to_many :sources,
:class_name => 'Vertex', :join_table => 'edges',
:foreign_key => 'sink_id', :association_foreign_key => 'source_id'
end
要使上述内容表现为 adirected 图形,请考虑插入边缘时插入互补边缘。另请注意,现在不建议使用has_and_belongs_to_many
,您可以使用has_many :sources ... :through => :edges
代替[source_id,sink_id]
。任何强制执行都可以通过验证(即顶点没有自身边缘)和/或数据库约束(edges
中ActiveRecord
上的unicity约束/索引确保顶点V1 ---&gt; ; V2不由多于一个有向边连接,并且顶点V1&lt; --- V2也不由一个以上的有向边连接。)
此时您有两个选项,具体取决于图表的大小以及您希望在任何给定时间点遍历的图表数量:
vertex1.edges.first.sink.edges
关系(例如RGL
...)在上述模型之上编写应用程序所需的最少量图形逻辑;这个将导致对数据库进行大量往返 edges = Edge.find(:all)
dg = RGL::AdjacencyGraph.new(edges.inject([]) { |adj,edge|
adj << edge.source_id << edge.sink_id
})
# have fun with dg
# e.g. isolate a subset of vertex id's using dg, then
# load additional info from the DB for those vertices:
vertices = Vertex.find(vertex_ids)
;选择从DB到RGL的所有顶点和边,并使用RGL进行图遍历,例如
Edge.find(:all)
以上将SQL语句的总数(在只读操作中)降为2,但如果图形(red
)很大,可能会对数据库或内存造成压力 - 此时你可能会考虑进一步限制实际需要的数据量,例如只关心 Edge.find(:all,
:joins => :sources, # or sinks; indifferent since symmetric
:conditions => [ 'vertices.red = ?', true ]
)
顶点的连接:
{{1}}