2011-11-02 46 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加入會降低性能。 –

相關問題