多對多關系是不同數據模型之間的重要區别特征。若數據大多是一對多(樹結構數據)或記錄之間無關系,則文檔模型最合适。但若多對多關系的數據很常見,關系模型能處理簡單的多對多,但随數據之間關聯複雜度增加,将數據建模轉化為圖模型更自然。
圖的組成:
很多數據能建模為圖。典型案例:
很多著名算法可在這些圖上運行。如汽車導航系統搜索道路網中任意兩點之間最短路徑, PageRank計算Web圖上網頁的流行度,從而确定搜索排名。
圖的頂點表示相同類型的事物(分别是人、網頁或交叉路口)。然而,圖不局限于這樣的同構數據,圖更為強大的用途在于提供了單個數據存儲區中保存完全不同類型對象的一緻性方式。如Facebook維護一個含許多不同類型的頂點與邊的大圖:
本文下圖示例
它可能來自社交網絡或某族譜數據庫。 案例是兩個人,分别來自愛達荷州的Lucy和來自法國波恩的Alain,它們結婚了,目前住在倫敦。
有多種不同但相關的方法可構建和查詢圖中的數據。本節将讨論屬性圖模型和三元存儲模型。
屬性圖在屬性圖模型中,每個頂點包括:
每個邊包括:
可将圖存儲作由兩個關系表組成,一個用頂點, 另一個用邊
此模式使用PostgreSQL JSON存儲每個頂點或邊的屬性)。為每個邊存儲頭部和尾部頂點,若想要頂點的入邊或出邊集合 ,可分别通過head_vertex 或tail_vertex來查edges表。
圖模型重點:
這些特性為數據建模提供靈活性,如圖1,顯示了一些傳統關系模式很難表達的東西,如不同國家的不同類型的地區結構(中國有省和區,而美國有縣和州),特殊曆史原因及不同粒度的數據( Lucy當前住所被指定為一個城市,而她的出生地則是州一級)。
可将這個圖擴展到包括許多關于Lucy 和 Alian的其他信息或其他人。例如,可用來表示他們的任何食物過敏(通過為每個過敏源引人頂點及人與過敏原之間的邊來表示過敏),并将過敏掘與頂點的集合聯結,這些頂點顯示哪些食物含有哪些物質。然後,可以編寫一個查詢找出每個人吃啥安全。圖有利于演化:向應用添加功能時,圖很容易擴展以适應數據結構的不斷變化。
-- 采用 Cypher 查詢從美國移民到歐洲的人員名單
MATCH
(person) -[:BORN_IN]-> ()-[:WITHIN*O..]->(us:Location{name:'United States'}),
(person) -[:LIVE S_IN ]->()-[: WITHIN*O..]- > (eu:Location{name:'Eu rope'})
RETURN person.name
示例2說名能使用關系數據庫表示圖數據,這是否意味着也支持SQL查詢?
答案是肯定的,但存在一些困難。在關系數據庫中,通常會預知查詢需要哪些join操作。而對于圖查詢, 找到要找的頂點前,可能需遍曆數量未知的邊,即join操作數量無法預知。
SQL1999标準後, 查詢過程中這種可變的遍曆路徑可使用“遞歸公用表表達
式”(即WITH RECURSIVE語法)來表示。示 2-5 采用該技術的SQL表達來執行相同的
查詢(查找從美國移民到歐洲的人員名單 ),目前PostgreSQL IBM DB2, Oracle
SQL Server 支持該技術 ,但與Cypher豐目比,語法仍顯得非常笨拙。
in usa(vertex_id) AS (
-- 首先找到name屬性值為United States的頂點,并将其作為頂點集in_usa中的第一個元素
SELECT vertex_id FROM vertces WHERE properties->>'name'='United States'
UNION
-- 沿集合in_usa中頂點的所有入邊within,并将它們添加到同一集合,直到遍曆所有入邊
SELECT edges.tail_vertex FROM edges
JOIN in_usa ON edges.head_vertex = in_usa.vertex_id WHERE edges.label='within'
);
-- in_europe is the set of vertex IDs of all locations within Europe
in europe(vertex_id) AS (
-- 從name屬性值為Europe的頂點開始執行同樣操作,并建立頂點集in_europe
SELECT vertex_id FROM vertices WHERE properties->>'name'='Europe'
UNION
SELECT edges.tail_vertex FROM edges
JOIN in_europe ON edges.head_vertex = in_europe.vertex_id
WHERE edges.label = 'within'
);
-- born_in_usa is the set of vertex IDs of all people born in the US
born_in_usa(vertex_id) AS (
-- 對in_usa集合中的每個頂點,按入邊born_in來查找出生在美國境内某地的人
SELECT edges.tail_vertex FROM edges
JOIN in_usa ON edges.head_vertex = in_usa.vertex_id
WHERE edges.label = 'born_in'
);
-- lives_in_europe is the set vertex IDs of all people living in Europe
lives_in_europe(vertex_id) AS (
-- 類似地,對in_europe集合中的每個頂點,按入邊lives_in來查找居住在歐洲的人
SELECT edges.tail_vertex FROM edges
JOIN in_europe ON edges.head_vertex = in_europe.vertex_id
WHERE edges.label = 'lives_in'
);
SELECT vertices . properties->>'name'
FROM vertices
-- join to find t ho se peo ple who were both born in the US *a nd * live i n Europe
-- 最後,通 join 把在美國出生的人的集合與在歐洲居住的人的集合相交
JOIN born_in_usa ON vertices.vertex_id = born_in_usa.vertex_id
JOIN lives_in_europe ON vertices.vertex_id = lives_in_europe.vertex_id;
若相同查詢可以用一種查詢語言寫4行代碼完成,而另一種查詢語需29行,足以說明不同數據模型适用不同場景。因此,選擇适合應用程序的數據模型很重要!
三元存儲與SPARQL三元存儲模式幾乎等同屬性圖模型,不同名詞描述相同思想而已。盡管如此,考慮到有多種針對三元存儲的工具 ,它們可能是構建應用程序寶貴補充,因此還是值得讨論。
三元存儲中,所有信息都以簡單的三部分形式存儲(主體,謂語,客體) 。如在三元組 (吉姆,喜歡,香蕉 )中:
圖的頂點被寫為_:someName。頂點的名字在定義文件以外沒有任何意義,隻是為區分三元組的不同頂點。謂語表示邊時,客體是另一個頂點,如 _:idaho :within _:usa 。當謂語表示一個屬性時,該客體則是一個字符串,如 _:usa :name "United States"
若定義相同主體的多個三元組,反複輸入相同單詞就略顯枯燥。可使用分号說明同一主體的 多個對象信息。這樣 Turtle 格式就更簡潔、可讀性強。以更簡潔語法重寫示例3:
若閱讀更多關于三元存儲的信息,很可能會被卷入關于語義網大量文章漩渦之中。
三元存儲數據模型其實完全獨立于語義網,例如,Datomic是個三元存儲,它和語義網并無任何關系年。但考慮到很多人覺得二兩者緊密相連,有必要澄清。
語義網,本質上源于一個簡單合理的想法:網站通常将信息以文字和圖片方式發布給人類閱讀,為何不把信息發布為機器可讀的格式給計算機閱讀呢?資源描述框架(Resource Description Framework, RDF)就是這樣一種機制, 它讓不同網站以一緻格式發布數據,這樣不同網站的數據自動合并成一個數據網絡,一種互聯網級别包含所有數據的數據庫。
但語義網在21世紀初被嚴重誇大,時至今日也未在實踐中見到任何靠譜實現,由此許多人開始懷疑。另外,還有其他一些方面批評,包括令人眼花缭亂的各種縮略詞、極其複雜的标準提議,以及過于自大的标榜。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!