當前,基於圖結構的數據(如下簡稱爲「圖數據」)無處不在。Facebook、Twitter 和 Pinterest 等企業已經看到並最大化地利用了這些相互關聯數據的強大之處。這直接致使了對圖數據解決方案關注度的提高,各類解決方案也與日俱增。redis
Redis 可加載模塊系統的推出,使咱們意識到在 Redis 工具集中引入圖數據結構的巨大潛力。Redis 採用原生 C 語言實現,側重於提供高性能特性。如今咱們經過開發 Redis,爲其新引入了圖數據庫能力。RedisGraph 以開源項目提供在 GitHub 上。數據庫
本文將介紹 RedisGraph 的一些內部設計和特性,並展現其當前所具有的能力。bash
RedisGraph 是一種基於 Redis 全新設計實現的圖數據庫。它使用了新的 Redis Modules API,擴展 Redis 並提供了一些新的命令和功能。其主要特性包括:簡單且快速的索引和查詢、在內存中存儲數據、使用了定製的內存高效數據結構、基於磁盤的數據持久化、以數據表形式給出的結果集、支持簡單並廣爲使用的圖查詢語言 Cypher,以及數據的過濾、聚合和排序等。微信
爲介紹 RedisGraph 的一些關鍵特性,下面咱們給出一個基於 redis-cli 工具運行的例子。數據結構
實體一般表示爲圖中的節點。本例建立了一個小規模的圖,圖中的實體爲演員和電影,以「參演」關係鏈接參演電影的演員和電影。使用 GRAPH.QUERY 命令發佈 CREATE 語句的格式以下,該語句實現將新的實體和關係添加到一個圖中。工具
下面一條命令建立了一個圖:性能
RedisGraph 實現了 openCypher 圖查詢語言的一個子集。儘管其中僅支持該語言的數個功能,可是對於從圖中抽取有用的信息而言,這些功能是徹底夠用的。使用 GRAPH.QUERY 命令執行查詢的命令格式爲:測試
GRAPH.QUERY <graph_id> <query>複製代碼
下面咱們在所建立的電影圖數據上執行一系列查詢。spa
其中,第一行是結果集的頭部信息,按 RETURN 語句命名各個列。第二行中包含了查詢的結果。設計
第二個查詢是找出每位演員參演了多少部電影。
不一樣的圖數據庫,可能採用了不一樣的結構表示圖。有的使用了鄰接列表,也有的使用了鄰接矩陣。每種表示結構都有其自身的優劣之處。對於 RedisGraph 而言,關鍵在於給出一種支持對圖作快速搜索的數據結構。咱們使用了一種稱爲「Hexastore」的結構保存圖中的全部關係。
Hexastore 的結構由一系列三元組組成。其中,每一個三元組包括以下三部分:
主語(Subject);
謂詞(Predicate);
目標(Object)。
主語表示源節點,謂詞表示關係,目標表示目的節點。對於圖中的每條關係,Hexastore 將保存源節點、關係邊和目的節點間全部可能存在的六種排列。如下面這條關係爲例:
(Aldis_Hodge)-[act]->(Straight_Outta_Compton)複製代碼
其中, Aldis_Hodge 是源節點,act 是關係,Straight_Outta_Compton 是目標節點。
該關係的六種可能排列以下:
SPO:Aldis_Hodge:act:Straight_Outta_Compton
SOP:Aldis_Hodge:Straight_Outta_Compton:act
POS:act:Straight_Outta_Compton:Aldis_Hodge
PSO:act:Aldis_Hodge:Straight_Outta_Compton
OPS:Straight_Outta_Compton:act:Aldis_Hodge
OSP:Straight_Outta_Compton:Aldis_Hodge:act複製代碼
一旦構建了 Hexastore,咱們能夠輕易地實現圖搜索。例如,若是要查找「Straight Outta Compton」電影中的演員,那麼能夠實現爲搜索 Hexastore 中全部包含前綴 OPS:Straight_Outta_Compton:act:* 的字符串。
若是要查找 Aldis Hodge 參演的全部電影,那麼能夠實現爲查找全部包含前綴 SPO:Aldis_Hodge:act:* 的字符串。
儘管 Hexastore 會佔用大量的內存,由於每條關係表示爲六個三元組,可是這樣的三元組數據結構不只支持快速搜索,並且能夠高效地使用內存,由於它並不會重複地生成已有的字符串前綴。
目前已經存在着一些圖查詢語言,咱們並不想從新造輪子,實現咱們本身的語言。所以,咱們決定實現最廣爲使用的圖查詢語言 openCyper 的一個子集。儘管 Open-Cypher 項目提供的語言解析器建立方法易於使用,但咱們仍是決定建立咱們本身的解析器。該解析器使用 Lex 做爲分詞器,並使用 Lemon 生成 C 目標解析器。
正如上面所說起的,咱們目前只支持該語言的一個子集。咱們將會繼續添加一些新能力,並擴展語言。
下面,咱們介紹 RedisGraph 中的模塊在執行查詢中的操做步驟。如下面的查詢爲例,該查詢找出全部 30 歲以上並與 Aldis Hodge 共同參演過影片的演員:
RedisGraph 將解析查詢、構建抽象語法樹、構建執行計劃(由標籤掃描操做、Filter 操做、Expand 操做、Expand into 操做等組成的)、執行計劃、將匹配的實體屬性添加到結果集中。
對於一個給定的有效查詢,解析器將會生成抽象語法樹。下列六類語句,會在抽象語法樹中分別生成對應的主節點:
MATCH
CREATE
DELETE
WHERE
RETURN
ORDER
生成抽象語法樹,是一種描述和結構化語言的通用方法。
查詢經過建立謂詞過濾出實體。以上面的查詢爲例,其中須要過濾掉小於 30 歲的演員。在查詢中,可使用 OR、AND 等關鍵字組合謂詞構造粒度條件。在運行時會根據 WHERE 語句構建過濾樹。過濾樹中的每一個節點能夠表示一個條件(例如 A>B),也能夠表示一個操做(AND 或 OR)。候選實體將經過過濾樹進行求值。
MATCH 語句描述了被查詢實體(即節點)間的關係。節點能夠具備別名,以支持執行查詢生命週期後期的引用(WHERE、RETURN 語句)。可是,最終還必須爲全部的節點指定一個 ID。對節點指定 ID 過程稱爲搜索階段。
搜索階段根據 MATCH 語句查詢 Hexastore,找出全部的 ID。以上面的查詢爲例,搜索階段以查找 Aldis Hodge 參演的電影爲開始。對於所搜索到的每部電影擴展搜索,找到當前電影的參演演員。
這樣的搜索過程能夠當作是一個遍歷圖的迭代過程。該迭代過程在每一步發現一個新 ID。一旦節點指定了 ID,就能夠確認當前的實體符合過濾語句的條件。這時能夠抽取 RETURN 語句中指定的請求屬性,並將新紀錄添加到最終結果集中。
插入一條新關係的複雜度是 O(1),RedisGraph 能夠在 1 秒內建立 10 萬條新關係。在不一樣的底層硬件上,測試結果可能會存在差別。
檢索數據的性能徹底取決於圖的規模,以及所執行的查詢類型。對於一個小規模圖,例如約 1000 個實體、2500 條邊,RedisGraph 每秒可執行約 6.5 萬次的「朋友的朋友」(FOAF)查詢。
須要指出的是,除了 Hexastore 以外,咱們並未對實體作索引。將來咱們將實現實體索引,這將會極大地下降查詢執行時間。
Redis-Graph 以 AGPL-3.0 許可發佈。
RedisGraph 項目儘管推出不久,但它已經能夠做爲圖數據庫的一個替代選項。RedisGraph 支持的操做子集能夠分析並探索圖數據。做爲一個 Redis 模塊,全部 Redis 客戶無需作出任何調整就可使用該模塊功能。咱們考慮繼續改進,並在開源社區的幫助下進一步擴展 RedisGraph。
查看英文原文:
http://redisgraph.io/design/
更多幹貨內容請關注微信公衆號「AI 前線」,(ID:ai-front)