簡體   English   中英

如何在關系數據庫中持久化圖形數據結構?

[英]How to persist a graph data structure in a relational database?

我考慮過創建一個 Vertices 表和一個 Edges 表,但是在 memory 中構建圖和遍歷子圖是否需要大量查找? 我想避免過多的數據庫讀取。 還有其他方法可以保留圖形嗎?

旁注:我聽說過 Neo4j,但我的問題實際上是如何在概念上表示標准數據庫中的圖形。 不過,我對一些 NoSQL 解決方案持開放態度,例如 mongodb。

遺憾的是答案:你的考慮在每個方面都是完全正確的。 您必須將節點(頂點)存儲在一個表中,並且Edges引用FromNode和ToNode以將圖形數據結構轉換為關系數據結構。 你也是對的,這最終會導致大量的查找,因為你無法將它分成子圖,可能會立即查詢。 您必須從節點遍歷到邊緣到節點到邊緣到節點...依此類推(遞歸,而SQL正在使用集合)。

重點是...

關系,面向圖,面向對象,基於文檔是滿足不同要求的不同類型的數據結構。 這就是它的全部內容以及為什么這么多不同的NoSQL數據庫(大多數都是簡單的文檔存儲)出現了,因為以關系方式組織大數據毫無意義。

備選1 - 面向圖形的數據庫

但是也有面向圖形的NoSQL數據庫,這使得圖形數據模型成為像OrientDB這樣的一流公民,我現在正在玩一點點。 關於它的好處是,盡管它將數據保存為圖形,但它仍然可以以關系或甚至面向對象或面向文檔的方式使用(即通過查詢普通的舊SQL)。 然而, 遍歷圖表是確保從中獲取數據的最佳方式。

備選方案2 - 使用內存中的圖形

在快速路由方面,像Graphhopper這樣的路由框架在內存中構建了完整的Graph(數十億節點)。 因為Graphhopper使用其GraphStore的MemoryMapped實現,甚至可以在僅需要一些MB內存的Android設備上運行。 完整的圖形在啟動時從數據庫讀入存儲器,然后在那里完成路由,因此您無需查找數據庫。

我遇到了同樣的問題,並決定最終使用以下結構,這需要2個數據庫查詢,然后其余的工作在內存中:

將節點存儲在表中並使用每個節點記錄引用該圖:

Table Nodes

id  | title | graph_id
---------------------
105 | node1 | 2
106 | node2 | 2

還將邊存儲在另一個表中,並再次引用這些邊所屬的圖與每個邊:

Table Edges

id | from_node_id | to_node_id | graph_id
-----------------------------------------
1  | 105          | 106        | 2
2  | 106          | 105        | 2

使用一個查詢獲取所有節點,然后使用另一個獲取所有邊緣。

現在構建您存儲圖形的首選方式(例如,鄰接列表)並繼續您的應用程序流程。

我不同意這里的其他帖子。 如果你有特殊的 class 有限制的圖,你通常可以通過更專業的設計(例如,每個頂點的邊數有限,只需要遍歷一種方式等)。

然而,對於存儲任意圖,關系數據庫是一個很好的選擇。 它們的設計具有令人難以置信的良好權衡,幾乎在所有情況下都表現良好。 此外,數據需求往往會隨着時間的推移而變化,而關系數據庫可以讓您輕松地更改存儲和查找,而無需更改數據表示。

讓我們回顧一下您的設計:

  • 一張頂點表(id,數據)
  • 一張邊表(startId、endId、數據)

首先觀察存儲效率,因為它與要存儲的數據成正比。 如果我們有 10 個頂點和 10 條邊,我們存儲 20 條信息。

現在,讓我們看看查找。 假設我們在頂點 id 上有一個索引,我們可以在至少log(n)中查找我們想要的任何數據(根據索引可能更好)。

  • 給定一個節點告訴我離開它的邊緣
  • 給定一個節點告訴我進入它的邊
  • 給定一條邊告訴我它來自或進入的節點

這就是您需要的所有基本查詢。

現在假設您有一個“圖形數據庫”,它存儲離開每個頂點的邊列表。 這使得每個頂點的大小可變。 它更容易遍歷。 但是,如果您想遍歷另一個方向怎么辦? 現在您還存儲了進入每個頂點的邊列表。 現在您有該信息的兩個副本,數據庫(或開發人員)必須做大量工作以確保它們永遠不會不同步。

O(log(n)) 與 O(1)

關系數據庫索引通常以排序的形式存儲數據,或者正如其他人指出的那樣,也可以使用 hash 表。 即使您堅持使用 sorted,它也會表現得很好。

首先請注意,big oh 衡量的是可伸縮性,而不是性能。 對於小數據集,哈希可能比許多循環慢。 即使散列O(1)更好,二分查找O(log2)也非常好。 此外,您可以在 30 個步驟中搜索十億條記錄。 它是緩存和分支預測器友好的。

將以前的答案添加到MS SQL Server 從2017年開始添加對Graph Architecture的支持這一事實。

它遵循所描述的具有節點邊緣表的模式(應該使用特殊的“AS NODE”和“AS EDGE”關鍵字創建)。 節點和邊表結構

它還有新的MATCH關鍵字介紹“支持模式匹配和遍歷圖形”這樣(朋友是邊緣表的名稱在下面的例子中):

SELECT Person2.name AS FriendName
FROM Person Person1, friend, Person Person2
WHERE MATCH(Person1-(friend)->Person2)
AND Person1.name = 'Alice';

關於redgate Hub上的SQL Server圖形數據庫,還有一組非常好的文章。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM