2011-09-24 161 views
18

我有一個關於在圖形數據庫中建模的一般問題,我似乎無法將我的頭圍繞。如何在圖形數據庫中建立真實世界的關係(如Neo4j)?

你如何塑造這種類型的關係:「牛頓發明微積分」?

simple graph,你可以喜歡這個型號:

Newton (node) -> invented (relationship) -> Calculus (node) 

...所以你有一堆,你增加了更多的人,發明的「發明」曲線關係。

的問題是,你開始需要一堆屬性添加到關係:

  • invention_date
  • influential_concepts
  • influential_people
  • books_inventor_wrote

...和您需要開始在這些屬性和其他節點之間創建關係,如:

  • influential_people:對人的關係節點
  • books_inventor_wrote:關係到預定節點

所以現在看起來像「真實世界的關係」(「發明」)實際上應該是一個節點圖形,圖形應該是這樣的:

Newton (node) -> (relationship) -> Invention of Calculus (node) -> (relationship) -> Calculus (node) 

而對於複雜的事情更多,其他人也參加微積分的發明,使圖表現在變成這樣的:

Newton (node) -> 
    (relationship) -> 
    Newton's Calculus Invention (node) -> 
     (relationship) -> 
     Invention of Calculus (node) -> 
      (relationship) -> 
      Calculus (node) 
Leibniz (node) -> 
    (relationship) -> 
    Leibniz's Calculus Invention (node) -> 
     (relationship) -> 
     Invention of Calculus (node) -> 
      (relationship) -> 
      Calculus (node) 

所以我問這個問題,因爲它看起來像你不想實際的圖形數據庫上設置屬性「的關係」對象,因爲你可能想在某個點將它們視爲圖中的節點。

這是正確的嗎?

我一直在研究Freebase Metaweb Architecture,他們似乎把所有東西當作一個節點。例如,Freebase的想法是Mediator/CVT,您可以在其中創建一個將「Actor」節點鏈接到「Film」節點的「Performance」節點,如下所示:http://www.freebase.com/edit/topic/en/the_last_samurai。不太確定這是否是同一個問題。

你有什麼指導原則可以用來確定「現實世界關係」是否應該實際上是一個圖節點而不是一個圖關係?

如果有關於這個話題的好書,我很想知道。謝謝!

回答

18

其中一些東西,如invention_date,可以存儲爲邊上的屬性,就像在大多數圖形數據庫中一樣,邊可以具有與頂點可以具有屬性相同的屬性。例如,你可以做這樣的事情(代碼如下TinkerPop's Blueprints):

Graph graph = new Neo4jGraph("/tmp/my_graph"); 
Vertex newton = graph.addVertex(null); 
newton.setProperty("given_name", "Isaac"); 
newton.setProperty("surname", "Newton"); 
newton.setProperty("birth_year", 1643); // use Gregorian dates... 
newton.setProperty("type", "PERSON"); 

Vertex calculus = graph.addVertex(null); 
calculus.setProperty("type", "KNOWLEDGE"); 

Edge newton_calculus = graph.addEdge(null, newton, calculus, "DISCOVERED"); 
newton_calculus.setProperty("year", 1666); 

現在,讓我們展開它一點點,並添加Liebniz:

Vertex liebniz = graph.addVertex(null); 
liebniz.setProperty("given_name", "Gottfried"); 
liebniz.setProperty("surnam", "Liebniz"); 
liebniz.setProperty("birth_year", "1646"); 
liebniz.setProperty("type", "PERSON"); 

Edge liebniz_calculus = graph.addEdge(null, liebniz, calculus, "DISCOVERED"); 
liebniz_calculus.setProperty("year", 1674); 

添加在書:

Vertex principia = graph.addVertex(null); 
principia.setProperty("title", "Philosophiæ Naturalis Principia Mathematica"); 
principia.setProperty("year_first_published", 1687); 
Edge newton_principia = graph.addEdge(null, newton, principia, "AUTHOR"); 
Edge principia_calculus = graph.addEdge(null, principia, calculus, "SUBJECT"); 

要找出牛頓在他發現的東西上寫的所有書籍,我們可以構造一個圖遍歷。我們從牛頓開始,遵循他發現的事物的鏈接,然後反向鏈接獲取有關該主題的書籍,並再次通過鏈接反向獲取作者。如果作者是牛頓,那麼回到書中並返回結果。該查詢是寫在Gremlin,爲圖遍歷一個基於Groovy領域特定語言:

newton.out("DISCOVERED").in("SUBJECT").as("book").in("AUTHOR").filter{it == newton}.back("book").title.unique() 

因此,我希望我已經證明了一點聰明的遍歷如何使用,以避免產生中間節點代表問題邊緣。在一個小型的數據庫中它並不重要,但是在一個大型數據庫中,你將會遇到大量的性能問題。

是的,很遺憾,您不能將邊與圖中的其他邊相關聯,但這是這些數據庫的數據結構的限制。有時將所有內容都作爲節點是有意義的,例如,在Mediator/CVT中,性能也具有更具體一些。個人可能只希望在評論中提到湯姆克魯斯在「最後的武士」中的表現。但是,對於大多數圖形數據庫,我發現某些圖遍歷的應用可以讓我從數據庫中獲得我想要的內容。

+0

優秀的答案!這真的爲我清除了一切,謝謝。 –