更多幹貨內容請關注微信公眾號“AI 前線”,(ID:ai-front)
當前,基於圖結構的資料(以下簡稱為“圖資料”)無處不在。Facebook、Twitter 和 Pinterest 等企業已經看到並最大化地利用了這些相互關聯資料的強大之處。這直接導致了對圖資料解決方案關注度的提升,各種解決方案也與日俱增。
Redis 可載入模組系統的推出,使我們意識到在 Redis 工具集中引入圖資料結構的巨大潛力。Redis 採用原生 C 語言實現,側重於提供高效能特性。現在我們通過開發 Redis,為其新引入了圖資料庫能力。RedisGraph 以開源專案提供在 GitHub 上。
本文將介紹 RedisGraph 的一些內部設計和特性,並展示其當前所具備的能力。
RedisGraph 是一種基於 Redis 全新設計實現的圖資料庫。它使用了新的 Redis Modules API,擴充套件 Redis 並提供了一些新的命令和功能。其主要特性包括:簡單且快速的索引和查詢、在記憶體中儲存資料、使用了定製的記憶體高效資料結構、基於磁碟的資料持久化、以資料表形式給出的結果集、支援簡單並廣為使用的圖查詢語言 Cypher,以及資料的過濾、聚合和排序等。
為介紹 RedisGraph 的一些關鍵特性,下面我們給出一個基於 redis-cli 工具執行的例子。
實體通常表示為圖中的節點。本例建立了一個小規模的圖,圖中的實體為演員和電影,以“參演”關係連線參演電影的演員和電影。使用 GRAPH.QUERY 命令釋出 CREATE 語句的格式如下,該語句實現將新的實體和關係新增到一個圖中。
下面一條命令建立了一個圖:
RedisGraph 實現了 openCypher 圖查詢語言的一個子集。儘管其中僅支援該語言的數個功能,但是對於從圖中抽取有用的資訊而言,這些功能是完全夠用的。使用 GRAPH.QUERY 命令執行查詢的命令格式為:
GRAPH.QUERY <graph_id> <query>複製程式碼
下面我們在所建立的電影圖資料上執行一系列查詢。
其中,第一行是結果集的頭部資訊,按 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)