您好,登錄后才能下訂單哦!
本篇內容主要講解“圖數據庫的工作原理是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“圖數據庫的工作原理是什么”吧!
首先,在我們深入研究什么是圖數據庫之前,讓我們定義這個術語。圖數據庫是一種“不僅僅是 SQL”(NoSQL,全程為Not Only SQL)的數據存儲。它們旨在以圖結構存儲和檢索數據。
使用的存儲機制可能因數據庫而異。一些 GDB 可能使用更傳統的數據庫結構,例如基于表,然后在頂部有一個圖形 API 層。其他的將是“原生”GDB——從存儲、管理和查詢到數據庫的整個構造維護數據的圖形結構。許多當前可用的圖形數據庫通過將實體之間的關系視為“一等公民”來做到這一點。
廣義上有兩種類型的 GDB,資源描述框架 (RDF)/三重存儲/語義圖數據庫和屬性圖數據庫。
RDF GDB 使用三元組的概念,它是由三個元素組成的語句:主語-謂語-賓語。
主語將是圖中的資源或節點,對象將是另一個節點或文字值,謂詞表示主題和對象之間的關系。節點或關系上沒有內部結構,一切都由唯一標識符以 URI 的形式標識。
這種結構背后的動機是交換和發布數據。
GDB 屬性專注于存儲接近邏輯模型的數據的概念。這反過來將基于數據本身所尋求的問題,并專注于使該表示盡可能高效地存儲和查詢。
與基于 RDF 的圖不同,節點和關系上有內部結構,可提供豐富的數據表示以及相關的元數據。
在本文的其余部分,我們將重點關注原生屬性圖數據庫,特別是 Neo4j。讓我們檢查一下主要組件。
屬性圖數據庫的主要組成部分如下:
節點:在圖論中也稱為頂點——構建圖的主要數據元素
關系:在圖論中也稱為邊——兩個節點之間的鏈接。它將有方向和類型。沒有關系的節點是允許的,沒有兩個節點的關系是不允許的
節點和關系
標簽:定義一個節點類別,一個節點可以有多個
屬性:豐富一個節點或關系,不可以為空值!
標簽、類型和屬性
許多開發人員都熟悉傳統的關系數據庫,其中數據存儲在定義良好的模式中的表中。
表中的每一行都是一個離散的數據實體。行中的這些元素之一通常用于定義其唯一性:主鍵。它可能是一個唯一的 ID,也可能是一個人的身份證號碼之類的東西。
然后我們通過一個稱為規范化的過程來減少數據重復。在規范化中,我們將引用(例如某人的地址)移動到另一個表中。因此,我們從代表實體的行到代表該人地址的行獲得了一個引用。
例如,如果某人更改了他們的地址,您不希望該人的地址到處都是多個版本,并且必須嘗試記住該人地址所在位置的所有不同實例。規范化確保您擁有一個版本的數據,因此您可以在一個地方進行更新。
然后當我們查詢時,我們要重構這個歸一化的數據。我們執行所謂的 JOIN 操作。
在我們的主實體行中,我們有一個主鍵,用于標識實體的 ID,比如說人。我們還有一個叫做外鍵的東西,它代表我們地址表中的一行。我們通過主鍵和外鍵連接這兩個表,并使用它在地址表中查找地址。這稱為 JOIN,這些 JOIN 在查詢時和讀取時完成。
當我們在關系數據庫中執行 JOIN 時,它是一個集合比較操作,我們在其中查看我們的兩組數據重疊的位置(在這種情況下,集合是人員表和地址表)。在高層次上,這就是傳統關系數據庫的工作方式。
讓我們快速瀏覽一下原生圖形數據庫及其工作原理。
我們談到了關系數據庫中的離散實體是表中的一行。在原生圖形數據庫中,該行相當于一個節點。它仍然是一個離散的實體,所以我們仍然有這個標準化的元素。
一個節點將是一個實體。如果我們有個人節點,我們將有一個人一個節點。我們會有一定程度的獨特性,比如說社會安全號碼。
然而,關鍵的區別在于,當我們將這個人節點連接到另一個離散實體(例如地址)時,我們會在這兩個點之間創建物理連接(也稱為關系)。
地址會有一個指針,說明連接到節點的關系的出站部分是什么?然后我們有另一個指向關系的入站部分的指針指向另一個節點。
因此,實際上,我們正在收集一組指針,這是這兩個實體之間物理連接的體現。這就是最大的不同。
在關系數據庫中,您將在讀取時使用連接重新構建數據,這意味著在查詢時,它會嘗試找出事物如何映射在一起。
在圖數據庫中,由于我們已經知道這兩個元素是相連的,所以我們不需要在查詢時查找映射。我們所做的只是跟蹤與其他節點的存儲關系。
這就是我們所說的無索引鄰接。與其他數據庫系統相比,這種無索引鄰接的概念是理解原生圖形數據庫性能優化的關鍵。
無索引鄰接意味著在局部圖遍歷期間,按照連接圖中節點的這些指針(關系),操作的性能不依賴于圖的整體大小。這取決于連接到您正在遍歷的節點的關系數量。
當我們說 JOIN 是一個集合操作(交集)時,我們使用關系數據庫中的索引來查看這兩個集合的重疊位置。這意味著 JOIN 操作的性能隨著表變大而開始變慢。
在大 O 符號術語中,這類似于使用索引的對數增長——類似于 O(log n) 并且隨著查詢中的 JOIN 數量呈指數增長。
另一方面,圖中的遍歷關系更多的是基于我們實際遍歷的節點中的關系數量的線性增長,而不是圖的整體大小。
這是圖數據庫為我們提供無索引鄰接的基本查詢時間優化。從性能的角度來看,當我們考慮原生圖形數據庫時,這確實是最重要的事情。
我們已經談到了圖形和關系數據庫之間的理論差異。現在讓我們開始看一些并排比較。
電影圖由一個數據集組成,該數據集由演員、導演、制片人、作家、評論家和電影組成,以及有關它們如何相互連接的信息。
電影數據集包括:
133個人節點/實體
38個電影節點/實體
上述實體之間的 253 個關系/連接,描述的連接例如:
導演電影的人
在電影中扮演的角色和扮演的角色
寫電影的人
制作電影的人
評論過電影并給出評分和摘要的人
跟隨另一個人的人
雖然它是一個相對較小的數據集,但它全面地描述了圖的力量。
首先我們來看看我們各自數據庫的數據模型。與所有數據模型一樣,它們的外觀最終取決于您提出的問題類型。所以讓我們假設我們要問以下類型的問題:
一個人演過哪些電影?
一個人與哪些電影有關?
一個人曾經合作過的所有合作演員是誰?
基于這些,以下是相關的潛在數據模型:
電影圖的實體關系數據模型電影圖的屬性圖數據模型
你會立刻發現一些東西——那些 ID 不見了!因為一旦我們知道那里有連接,我們就將數據連接在一起,我們不再需要它們,或者那些映射表來讓我們知道不同的數據行如何連接在一起。
現在讓我們繼續比較一些查詢。從:PLAY movies示例中選取一些最初的查詢,讓我們看一下 Cypher 查詢的一些并排比較,以及等效的 SQL 查詢是什么樣的。
什么是 Cypher,我聽到你問?Cypher 是一種圖查詢語言,用于查詢 Neo4j 圖數據庫。還有一個OpenCypher版本,許多其他供應商都在使用它。
隨著我們進行查詢,它應該開始變得更加清晰,圖數據庫以及一種幫助探索關系的查詢語言是如何真正開始發揮作用的。讓我們開始尋找湯姆漢克斯吧!
MATCH (p:Person {name: "Tom Hanks"}) RETURN p
Cypher
SELECT * FROM person WHERE person.name = "Tom Hanks"
SQL
MATCH (:Person {name: “Tom Hanks”})-->(m:Movie) RETURN m.title
SELECT movie.title FROM movie INNER JOIN movie_person ON movie.movie_id = person_movie.movie_id INNER JOIN person ON person_movie.person_id = person.person_id WHERE person.name = "Tom Hanks"
MATCH (:Person {name: "Tom Hanks"})-[:DIRECTED]->(m:Movie) RETURN m.title
SELECT movie.title FROM movie INNER JOIN person_movie ON movie.movie_id = person_movie.movie_id INNER JOIN person ON person_movie.person_id = person.person_id INNER JOIN involvement ON person_movie.involve_id = involvement.involve_id WHERE person.name = "Tom Hanks" AND involvement.title = "Director"
MATCH (:Person {name: "Tom Hanks"})-->(:Movie)<-[:ACTED_IN]-(coActor:Person) RETURN coActor.name
WITH tom_movies AS ( SELECT movie.movie_id FROM movie INNER JOIN person_movie ON movie.movie_id = person_movie.movie_id INNER JOIN person ON person_movie.person_id = person.person_id WHERE person.name = "Tom Hanks") SELECT person.name FROM person INNER JOIN person_movie ON tom_movies = person_movie.movie_id INNER JOIN person ON person_movie.person_id = person.person_id INNER JOIN involvement ON person_movie.involve_id = involvement.involve_id WHERE involvement.title = "Actor"
希望您能了解 Cypher 和 SQL 查詢之間的差異。也許您也很高興了解更多關于它們的信息!我們將在博客文章中進一步提供一些參考。
現在,讓我們看看您可以在:PLAY movies圖表示例中找到的其他一些 Cypher 查詢,并解釋發生了什么。
沒有典型的培根數問題,任何電影圖表都是不完整的,我們的電影圖表也不例外!
到目前為止,我們看到的例子每次都遍歷一個關系。我們可以輕松地利用這些“寫入時連接”來遍歷許多關系來回答有趣的問題。
所以,回到凱文培根的數字。以下查詢將從 Kevin Bacon 人物節點開始,然后從該起點出發最多 4 跳,以帶回所有連接的電影和人物。
MATCH (bacon:Person {name:"Kevin Bacon"})-[*1..4]-(hollywood) RETURN DISTINCT hollywood
我們可以通過使用*1..4查詢模式的關系部分的語法來做到這一點:
* 表示一切
1..4 表示范圍 - 1 表示距離 1 跳,4 表示最多 4 跳
我們可以在這個電影數據集上做的另一件事是兩個節點之間的最短路徑。
在這個例子中,讓我們找出Kevin Bacon 和 Meg Ryan 之間的最短路徑。您會發現我們*再次將語法用于關系模式——指示一切。
對您來說可能是新的東西是p=. 您已經看到我們如何使用節點的引用(例如bacon或meg在我們當前的查詢中),并且我們可以對關系執行相同的操作。
我們還可以對整個路徑(即所有涉及的節點和關系)進行引用。我們為此使用的語法是refName =,在本例中是p=。
我們還使用 Cypher 函數shortestPath()——這是一個簡單的最短路徑函數,它將返回兩個指定節點之間的第一個最短路徑。請注意,可能還有另一條同樣短的路徑,但這個簡單的函數只會帶回遇到的第一個路徑。
對于那些對其他路徑相關功能感興趣的人,請查看 APOC 和 GDS 中可用的功能。
MATCH p=shortestPath( (bacon:Person {name:"Kevin Bacon"})-[*]-(meg:Person {name:"Meg Ryan"})) RETURN p
給大家一個警告:您可能會看到這一點,[*]并試圖在沒有shortestPath()函數或1..4范圍約束的情況下運行您的圖形。但這很可能會導致一些意想不到的事情。
在我們與 Kevin Bacon 和 Meg Ryan 的示例中,即使在這個非常小的數據集中只有 253 個關系,節點和關系之間的所有可能的路徑組合也很容易遇到 Bacon 和 Ryan 之間的數百萬條不同的路徑。
當使用*在你的關系作為查詢的一部分,非常謹慎使用!這個問題沒有提出最短路徑,因為當遇到比當前識別的最短路徑更長的潛在路徑時,它會立即被丟棄。
這里有兩個查詢真正展示了圖形數據庫的強大功能,我們可以輕松地使用數據中的連接來提出一些建議。
在我們的第一個查詢中,我們正在為湯姆漢克斯尋找新的合作演員,以與他尚未合作的人合作。查詢通過以下方式執行此操作:
首先,找到他已經合作過的所有合作演員
然后,找出所有的co-actors的co-actors(簡稱co-co-actors)
接下來,我們要排除那些已經和湯姆合作過的合作演員,并確保合作演員不是湯姆本人
最后,我們返回建議的合作演員姓名,我們將對其進行排序,但與他們合作的合作演員的數量 - 與該合作演員合作的合作演員越多,建議越好。
MATCH (tom:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors), (coActors)-[:ACTED_IN]->(m2)<-[:ACTED_IN]-(cocoActors) WHERE NOT (tom)-[:ACTED_IN]->()<-[:ACTED_IN]-(cocoActors) AND tom <> cocoActors RETURN cocoActors.name AS Recommended, count(*) AS Strength ORDER BY Strength DESC
太好了,所以我們找到了一些潛在的合作演員。在下一個查詢中,我們想推薦湯姆克魯斯作為湯姆漢克斯合作的潛在新合作演員。但是,誰來介紹這些湯姆斯呢?回到我們去的電影圖表。
在這個查詢中,我們:
找到湯姆漢克斯的合作演員,然后找出哪些合作演員也和湯姆克魯斯合作過
然后我們將返回合作演員以及他們與湯姆漢克斯和湯姆克魯斯共同出演的電影
MATCH (tom:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors), (coActors)-[:ACTED_IN]->(m2)<-[:ACTED_IN]-(cruise:Person {name:"Tom Cruise"}) RETURN tom, m, coActors, m2, cruise
到此,相信大家對“圖數據庫的工作原理是什么”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。