圖數(shù)據(jù)庫(kù)
??在如今數(shù)據(jù)庫(kù)群雄逐鹿的時(shí)代中,非關(guān)系型數(shù)據(jù)庫(kù)(NoSQL)已經(jīng)占據(jù)了半壁江山,而圖數(shù)據(jù)庫(kù)(Graph Database)更是攻城略地,成為其中的佼佼者。
??所謂圖數(shù)據(jù)庫(kù),它應(yīng)用圖理論(Graph Theory)可以存儲(chǔ)實(shí)體的相關(guān)屬性以及它們之間的關(guān)系信息。最常見(jiàn)例子就是社會(huì)網(wǎng)絡(luò)中人與人之間的關(guān)系。相比于關(guān)系型數(shù)據(jù)庫(kù)(比如MySQL等),圖數(shù)據(jù)庫(kù)更能勝任這方面的任務(wù)。
??圖數(shù)據(jù)庫(kù)現(xiàn)已涌現(xiàn)出許多出眾的軟件,比如筆者寫(xiě)過(guò)的文章Neo4j入門(mén)之中國(guó)電影票房排行淺析中的Neo4j,Twitter為進(jìn)行關(guān)系數(shù)據(jù)分析而構(gòu)建的FlockDB,高度可擴(kuò)展的分布式圖數(shù)據(jù)庫(kù)JanusGraph以及Google的開(kāi)源圖數(shù)據(jù)庫(kù)Cayley等。
??本文將具體介紹Cayley圖數(shù)據(jù)庫(kù)。
Cayley圖數(shù)據(jù)庫(kù)的簡(jiǎn)介

??Cayley圖數(shù)據(jù)庫(kù)是 Google 的一個(gè)開(kāi)源圖(Graph)數(shù)據(jù)庫(kù),其靈感來(lái)自于 Freebase 和 Google 的知識(shí)圖譜背后的圖數(shù)據(jù)庫(kù)。它采用Go語(yǔ)言編寫(xiě)而成,運(yùn)行命令簡(jiǎn)單,一般只需要3到4個(gè)命令即可。同時(shí),它擁有RESTful API,內(nèi)建查詢編輯器和可視化界面,支持多種查詢語(yǔ)言,比如JavaScript,MQL等。另外,它還能支持多種后端數(shù)據(jù)庫(kù)儲(chǔ)存,比如MySQL,MongoDB, LevelDB等,性能良好,測(cè)試覆蓋率也OK,功能十分豐富且強(qiáng)大。
??當(dāng)然,對(duì)于我們而言,最重要的特性應(yīng)該是開(kāi)源。Cayley圖數(shù)據(jù)庫(kù)的官方Github地址為:https://github.com/cayleygraph/cayley 。
??下面將具體介紹如何安裝及使用Cayley圖數(shù)據(jù)庫(kù)。
安裝及說(shuō)明
??關(guān)于Cayley圖數(shù)據(jù)庫(kù)的安裝,不同的操作系統(tǒng)的安裝方式不一樣。下載的網(wǎng)址為:https://github.com/cayleygraph/cayley/releases, 截圖如下:

讀者可依據(jù)自己的電腦系統(tǒng)下載相應(yīng)的文件,筆者的電腦為Mac,因此選擇cayley_0.7.5_darwin_amd64.tar.gz文件。同時(shí)你的電腦上需要安裝一款Cayley用來(lái)儲(chǔ)存后臺(tái)數(shù)據(jù)的數(shù)據(jù)庫(kù),筆者選擇了MongoDB數(shù)據(jù)庫(kù)。
??當(dāng)然,Cayley還為你提供了完整的使用說(shuō)明文檔,可以參考網(wǎng)址:https://github.com/cayleygraph/cayley/blob/master/docs/Quickstart-As-Application.md, 它能幫你快速熟悉Cayley的操作,助你快快上手。筆者會(huì)用更簡(jiǎn)單的方式幫你熟悉該圖數(shù)據(jù)庫(kù)。
??So, let's begin!
數(shù)據(jù)準(zhǔn)備
??為了能夠更好地了解Cayley圖數(shù)據(jù)庫(kù),我們應(yīng)該從數(shù)據(jù)開(kāi)始一步步地來(lái)構(gòu)建圖數(shù)據(jù)庫(kù),并實(shí)現(xiàn)查詢功能。本文的數(shù)據(jù)來(lái)源于文章Neo4j入門(mén)之中國(guó)電影票房排行淺析, 其中爬取了中國(guó)電影票房信息,如下:

以及每部電影中的主演信息,如下:

得到了兩個(gè)表格文件movies.csv和actor.csv,文件的內(nèi)容如下:


數(shù)據(jù)準(zhǔn)備完畢。如讀者需要下載該數(shù)據(jù),可以參考網(wǎng)址:https://github.com/percent4/Neo4j_movie_demo 。
三元組文件
??Cayley數(shù)據(jù)庫(kù)支持三元組文件導(dǎo)入,所謂三元組,指的是主語(yǔ)subject,謂語(yǔ)predicate 以及賓語(yǔ)object,每個(gè)三元組為一行。
??Cayley數(shù)據(jù)庫(kù)支持的三元組文件以nq為后綴,每個(gè)三元組為一行,主語(yǔ)、謂語(yǔ)、賓語(yǔ)中間用空格分開(kāi),同時(shí)還需要注意一下事項(xiàng)(筆者親自踩坑的經(jīng)歷):
- 注意空格,空格是劃分實(shí)體的標(biāo)志;
- 注意","是關(guān)鍵字,也不能在實(shí)體中出現(xiàn);
- 不能在實(shí)體中出現(xiàn)換行符(比如\n);
- 不能出現(xiàn)重復(fù)的數(shù)據(jù)(實(shí)體重復(fù)、三元組重復(fù)都不行)。
??接著我們利用Python程序?qū)ovies.csv和actors.csv文件處理成三元組。我們抽取的原則如下:
- 電影名,演員名為實(shí)體;
- 電影名與電影的關(guān)系為ISA,即電影名 ISA Movie;
- 演員名與電影名的關(guān)系為ACT_IN,即演員名 ACT_IN 電影名;
- 電影名的其余為屬性對(duì),即電影名 屬性 屬性名, 比如戰(zhàn)狼2 rank 1.
??實(shí)現(xiàn)的Python程序如下:
# -*- coding: utf-8 -*-
import pandas as pd
# 讀取文件
movies = pd.read_csv('movies.csv')
actors = pd.read_csv('actors.csv')
# print(movies.head())
# 處理電影數(shù)據(jù)為三元組,抽取的三運(yùn)組如下:
# 電影名 ISA Movie
# 電影名 屬性 屬性值
with open('China_Movie.nq', 'w') as f:
name_df = movies['name']
for i in range(name_df.shape[0]):
f.write('<%s> <ISA> <Movie> .\n'%name_df[i])
for col in movies.columns:
if col != 'name':
f.write('<%s> <%s> "%s" .\n'%(name_df[i], col, movies[col][i]))
# 處理演員數(shù)據(jù)為三元組,抽取的三運(yùn)組如下:
# 演員名 ISA Actor
# 演員名 ACT_IN 電影名
with open('China_Movie.nq', 'a') as f:
for i in range(actors.shape[0]):
for actor in actors['actors'][i].split(','):
f.write('<%s> <ACT_IN> <%s> .\n' % (actor, actors['name'][i]))
在China_Movie.nq中,共有276個(gè)三元組,文件的前幾行如下:
<戰(zhàn)狼2> <ISA> <Movie> .
<戰(zhàn)狼2> <rank> "1" .
<戰(zhàn)狼2> <src> "/item/%E6%88%98%E7%8B%BC2" .
<戰(zhàn)狼2> <box_office> "56.83億" .
<戰(zhàn)狼2> <avg_price> "35" .
<戰(zhàn)狼2> <avg_people> "38" .
<戰(zhàn)狼2> <begin_date> "2017.07.27" .
<流浪地球> <ISA> <Movie> .
<流浪地球> <rank> "2" .
<流浪地球> <src> "/item/%E6%B5%81%E6%B5%AA%E5%9C%B0%E7%90%83" .
<流浪地球> <box_office> "40.83億" .
<流浪地球> <avg_price> "46" .
<流浪地球> <avg_people> "50" .
<流浪地球> <begin_date> "2019.02.05" .
<紅海行動(dòng)> <ISA> <Movie> .
導(dǎo)入數(shù)據(jù)
??將China_Movie.nq文件移動(dòng)至Cayley的data目錄下,同時(shí)配置cayley_example.yml文件,內(nèi)容如下:
store:
# backend to use
backend: mongo
# address or path for the database
address: "localhost:27017"
# open database in read-only mode
read_only: false
# backend-specific options
options:
nosync: false
query:
timeout: 30s
load:
ignore_duplicates: false
ignore_missing: false
batch: 10000
在該配置文件中,聲明了Cayley的后臺(tái)數(shù)據(jù)庫(kù)為MongoDB,同時(shí)制定了ip及端口。
??接著運(yùn)行命令:
./cayley load -c cayley_example.yml -i data/China_Movie.nq
等待數(shù)據(jù)導(dǎo)入,接著前往MongoDB中查看,如發(fā)現(xiàn)MongoDB中存在cayley數(shù)據(jù)庫(kù),則表明數(shù)據(jù)導(dǎo)入成功。

使用查詢語(yǔ)句
??接著再輸入命令:
./cayley http -i ./data/China_Movie.nq -d memstore --host=:64210
這樣就支持在瀏覽器中進(jìn)行查詢了,只需要在瀏覽器中輸入http://localhost:64210/ 即可,界面如下:

??關(guān)于查詢語(yǔ)句,它是圖數(shù)據(jù)庫(kù)的精華所在,而對(duì)于Cayley而言,它的查詢語(yǔ)句相對(duì)來(lái)說(shuō)就比較簡(jiǎn)單且好理解,具體的查詢語(yǔ)句命令可以參考官網(wǎng): https://github.com/cayleygraph/cayley/blob/master/docs/GizmoAPI.md
,本文將通過(guò)幾個(gè)簡(jiǎn)單的查詢語(yǔ)句來(lái)說(shuō)明怎樣對(duì)Cayley圖數(shù)據(jù)庫(kù)進(jìn)行查詢。
查詢一共有多少條數(shù)據(jù)
命令為:
var n = g.V().Count();
g.Emit(n);
其中g(shù)代表圖,V代表頂點(diǎn),g.Emit()會(huì)將結(jié)果以JSON格式返回。輸出的結(jié)果如下:
{
"result": [
521
]
}
查詢?nèi)侩娪?/h5>
命令為:
var movies = g.V('<Movie>').In('<ISA>').ToArray();
g.Emit(movies);
返回的結(jié)果如下:
{
"result": [
[
"<戰(zhàn)狼2>",
"<流浪地球>",
"<紅海行動(dòng)>",
"<唐人街探案2>",
"<美人魚(yú)>",
"<我不是藥神>",
"<速度與激情8>",
"<西虹市首富>",
"<捉妖記>",
"<速度與激情7>",
"<復(fù)仇者聯(lián)盟3:無(wú)限戰(zhàn)爭(zhēng)>",
"<捉妖記2>",
"<羞羞的鐵拳>",
"<海王>",
"<變形金剛4:絕跡重生>",
"<前任3:再見(jiàn)前任>",
"<瘋狂的外星人>",
"<毒液:致命守護(hù)者>",
"<功夫瑜伽>",
"<侏羅紀(jì)世界2>"
]
]
}
查詢電影《流浪地球》的所有屬性值
命令為:
var movie = "<流浪地球>";
var attrs = g.V(movie).OutPredicates().ToArray(); //類(lèi)型為object,即字典
values = new Array();
for (i in attrs) {
var value = g.V(movie).Out(attrs[i]).ToValue();
values[i] = value;
}
key_val_json = new Object();
for (i in attrs) {
key_val_json[attrs[i]]= values[i];
}
g.Emit(key_val_json)
輸出結(jié)果如下:
{
"result": [
{
"<ISA>": "<Movie>",
"<avg_people>": "50",
"<avg_price>": "46",
"<begin_date>": "2019.02.05",
"<box_office>": "40.83億",
"<rank>": "2",
"<src>": "/item/%E6%B5%81%E6%B5%AA%E5%9C%B0%E7%90%83"
}
]
}
查詢沈騰主演的電影
命令為:
var movies = g.V('<沈騰>').Out('<ACT_IN>').ToArray();
g.Emit(movies);
輸出為:
{
"result": [
[
"<西虹市首富>",
"<羞羞的鐵拳>",
"<瘋狂的外星人>"
]
]
}
查詢《捉妖記》與《捉妖記2》的共同演員
命令為:
var actors1 = g.V('<捉妖記>').In('<ACT_IN>');
var actors2 = g.V('<捉妖記2>').In('<ACT_IN>');
var common_actor = actors2.Intersect(actors1).ToArray();//集合交集
g.Emit(common_actor);
輸出為:
{
"result": [
[
"<白百何>",
"<井柏然>",
"<曾志偉>",
"<吳君如>"
]
]
}
總結(jié)
??在本文中,筆者介紹了一種新的圖數(shù)據(jù)庫(kù)Cayley,并介紹了它的安裝方式,以及如何導(dǎo)入三元組數(shù)據(jù),進(jìn)行查詢。希望能夠給讀者一些參考~
??雖然是Google開(kāi)源的圖數(shù)據(jù)庫(kù),但在網(wǎng)上關(guān)于Cayley圖數(shù)據(jù)庫(kù)的介紹并不多,而且都未能深入地講解,大多是照搬官方文檔的講解,希望筆者的講解能夠帶來(lái)一些進(jìn)步,這也是筆者寫(xiě)此文的目的。希望此文能多少幫到讀者~
注意:不妨了解下筆者的微信公眾號(hào): Python爬蟲(chóng)與算法(微信號(hào)為:easy_web_scrape), 歡迎大家關(guān)注~