使用Neo4j+InteractiveGraph實現(xiàn)豆瓣電影知識圖譜可視化

電影知識圖譜

0.介紹

本文基于豆瓣電影數(shù)據(jù)構(gòu)建了一個電影知識圖譜色解。其中包括電影坷檩、演員批糟、導演三種節(jié)點及相關(guān)關(guān)系庶柿。并使用InteractiveGraph對圖譜完成可視化工作。

  • 數(shù)據(jù)豐富,圖譜包含2.7萬個節(jié)點冀膝,5萬條關(guān)系
  • 使用Neo4j圖數(shù)據(jù)庫進行圖存儲
  • 支持大圖全局可視化預(yù)覽
  • 支持節(jié)點關(guān)聯(lián)發(fā)現(xiàn)
  • 支持節(jié)點展開瀏覽可視化

所用到的程序包括:

1.數(shù)據(jù)處理

該數(shù)據(jù)來自openKG(http://www.openkg.cn/dataset/douban-movie-kg)唁奢,抽取自豆瓣電影。示例數(shù)據(jù)如下窝剖,包括電影的標題麻掸、封面、分類赐纱、語言基本信息以及導演脊奋、編劇和主演等人員信息。

豆瓣電影

{
  "id": 1292052, 
  "title": "肖申克的救贖",
  "url": "http://movie.douban.com/subject/1292052/", 
  "cover": "http://img3.douban.com/view/movie_poster_cover/lpst/public/p480747492.jpg", 
  "rate": 9.6, 
  "director": ["弗蘭克·德拉邦特"],
  "composer": ["弗蘭克·德拉邦特", "斯蒂芬·金"], 
  "actor": ["蒂姆·羅賓斯", "摩根·弗里曼", "鮑勃·岡頓", "威廉姆·賽德勒",  "克蘭西·布朗", "吉爾·貝羅斯", "馬克·羅斯頓", "詹姆斯·惠特摩", "杰弗里·德曼", "拉里·布蘭登伯格", "尼爾·吉恩托利", "布賴恩·利比", "大衛(wèi)·普羅瓦爾", "約瑟夫·勞格諾", "祖德·塞克利拉"], 
  "category": ["劇情", "犯罪"], 
  "district": ["United States of America_美國"], 
  "language": ["英語"], 
  "showtime": 1994.0, 
  "length": 142.0, 
  "othername": ["月黑高飛(港)", "刺激1995(臺)", "地獄諾言", "鐵窗歲月", "消香克的救贖"]
 }

數(shù)據(jù)集為JSON格式疙描,在導入Neo4j之前還需要做一些處理诚隙。
首先使用Pandas讀入數(shù)據(jù)集:

import pandas as pd
import numpy as np
# 讀入數(shù)據(jù)集
data = pd.read_json('data/dbmovies.json', dtype=object)

由于最終構(gòu)建的圖譜包含電影和人這兩類節(jié)點,因此需要將人物信息從電影信息中抽取出來起胰。觀察數(shù)據(jù)集可以發(fā)現(xiàn)久又,人物信息出現(xiàn)在主演、導演和編劇這三個字段中效五,所以需要將這三類信息轉(zhuǎn)換成邊信息并合并出人員節(jié)點數(shù)據(jù)地消。

以演員為例,首先把原數(shù)據(jù)中actor中的演員集合轉(zhuǎn)換成包含<電影id畏妖,演員姓名>這兩列的DataFrame脉执,然后導出為CSV文件作為邊數(shù)據(jù)。導出為CSV是因為方便Neo4j導入戒劫。

有了邊數(shù)據(jù)之后适瓦,將這三類人物提取到一列并做去重。這里忽略了演員之間同名的問題谱仪,姑且認為同名的人是同一個人玻熙。同樣的,把合并的數(shù)據(jù)也轉(zhuǎn)換成CSV格式作為人員節(jié)點數(shù)據(jù)疯攒。

person = pd.DataFrame()
labels = ['actor', 'director', 'composer']
for label in labels:
    df = data[['id', label]]
    df = df.dropna(axis=0, how='any')
    df = pd.DataFrame({'id': df['id'].repeat(df[label].str.len()),
                       label: np.concatenate(df[label].values)})
    person = pd.concat([person, df[label]], axis=0)
    df.to_csv('data/'+label+'.csv', index=False)

person.drop_duplicates(inplace=True, ignore_index=True)
person.to_csv('data/person.csv', index=False)

對人員信息處理完之后嗦随,需要對電影信息做處理。這里主要是把像電影語言這樣的數(shù)組信息轉(zhuǎn)換成字符串敬尺。同樣的也要導出到CSV作為電影節(jié)點文件枚尼。

data.drop(labels, axis=1, inplace=True)
list_labels = ['category', 'district', 'language', 'othername']
for list_label in list_labels:
    data[list_label] =  data[list_label].apply(lambda x: '、'.join(x) if x!=None else x)
data.to_csv('data/movie.csv', index=False)

2.導入數(shù)據(jù)

下面開始導入數(shù)據(jù)到Neo4j中砂吞。首先把所有導出的CSV文件拷貝到Neo4j安裝目錄下的import目錄中署恍,并啟動Neo4j。
使用如下Cypher導入電影節(jié)點數(shù)據(jù)蜻直。需要注意的是對評分盯质、上映年份袁串、時長這些數(shù)值類數(shù)據(jù)做處理,否則這些字段的數(shù)據(jù)自動作為字符串呼巷,無法計算囱修。

USING PERIODIC COMMIT 500
LOAD CSV WITH HEADERS FROM 'file:///movie.csv' AS line
CREATE (:Movie{
  id: line.id,
  name: line.title,
  url: line.url,
  image: line.cover,
  rate: toFloat(line.rate),
  category: line.category,
  district: line.district,
  language: line.language,
  showtime: toInteger(line.showtime),
  length: toInteger(line.length),
  othername: line.othername
})

導入人物數(shù)據(jù):

USING PERIODIC COMMIT 500
LOAD CSV FROM 'file:///person.csv' AS line
CREATE (:Person{name:line[0]})

在創(chuàng)建關(guān)系之前,需要對節(jié)點字段做索引王悍,這樣能加快創(chuàng)建關(guān)系節(jié)點查找的速度破镰。

CREATE INDEX ON :Movie(id)
CREATE INDEX ON :Movie(name)
CREATE INDEX ON :Person(name)

創(chuàng)建三種關(guān)系,分別是(人物)-[:飾演]->(電影)压储,(人物)-[:導演]->(電影)(人物)-[:編劇]->(電影)鲜漩。

USING PERIODIC COMMIT 500
LOAD CSV WITH HEADERS FROM 'file:///actor.csv' AS line
MATCH (p:Person) where p.name = line.actor WITH p,line
MATCH (m:Movie) where m.id = line.id 
MERGE (p)-[:play]->(m)
USING PERIODIC COMMIT 500
LOAD CSV WITH HEADERS FROM 'file:///director.csv' AS line
MATCH (p:Person) where p.name = line.director WITH p,line
MATCH (m:Movie) where m.id = line.id 
MERGE (p)-[:direct]->(m)
USING PERIODIC COMMIT 500
LOAD CSV WITH HEADERS FROM 'file:///composer.csv' AS line
MATCH (p:Person) where p.name = line.composer WITH p,line
MATCH (m:Movie) where m.id = line.id 
MERGE (p)-[:write]->(m)

這一步對人物做了一個打分計算,把人物參與的(可以是參演集惋、編劇或?qū)а?電影評分的均值作為人物的評分宇整。

match (p:Person)-[]-(m:Movie) with p,avg(m.rate)*10 as avg
set p.rate = round(avg)/10

3.配置可視化系統(tǒng)

本文使用的知識圖譜可視化系統(tǒng)包括兩個部分:InteractiveGraph和InteractiveGraph-neo4j,前者為可視化系統(tǒng)的Web前端部分芋膘,負責顯示和交互;后者為可視化系統(tǒng)的后端部分霸饲,負責管理數(shù)據(jù)以及提供各種數(shù)據(jù)訪問接口为朋。

InteractiveGraph-neo4j安裝與配置

下載與部署

首先從github下載最新的發(fā)行版war包:https://github.com/grapheco/InteractiveGraph-neo4j/releases
將下載完成的war包放到Tomcat的webapps目錄中,tomcat會自動解壓war包生成graphserver文件夾(如果沒有自動解壓可以嘗試重啟Tomcat)厚脉。

修改配置文件

修改配置文件graphserver/WEB_INF/conf1.properties

allowOrigin=*
backendType=neo4j-bolt
neo4j.boltUrl=bolt://localhost:7687
neo4j.boltUser=neo4j
neo4j.boltPassword=1
neo4j.regexpSearchFields=name
neo4j.strictSearchFields=label:name
neo4j.nodeCategories=Person:人物,Movie:電影
layout_on_startup=false
visNodeProperty.label==$prop.name
visNodeProperty.value==$prop.rate
visNodeProperty.image==$prop.image
visNodeProperty.x    ==$prop.x
visNodeProperty.y    ==$prop.y
visNodeProperty.info=<p align=center> #if($prop.image) <img width=150 src="${prop.image}"><br> #end <b>${prop.name}</b></p><p align=left><ul><li>評分:${node.rate}</li><li>類型:${node.category}</li><li>時長:${node.length}分鐘</li><li>語言:${node.language}</li></ul></p>

其中:

  • allowOrigin:是允許訪問的域习寸,默認允許所有,這里不需要修改傻工;
  • backendType:后端類型霞溪,本文使用的是neo4j因此也不需要修改;
  • neo4j.boltUrl:Neo4j的地址中捆;
  • neo4j.boltUser:Neo4j用戶名鸯匹;
  • neo4j.boltPassword:Neo4j密碼;
  • neo4j.regexpSearchFields:這一項是搜索時匹配的字段名泄伪,在這里指定為節(jié)點的name字段殴蓬;
  • neo4j.strictSearchFields:嚴格搜索的接受格式,這里設(shè)置為節(jié)點label:name字段(如Person:周星馳)蟋滴;
  • neo4j. nodeCategories:這一項指定數(shù)據(jù)庫中有哪些節(jié)點類型染厅,本文中有人物和電影;
  • layout_on_startup:是否自動布局津函。本文中數(shù)據(jù)有幾萬個節(jié)點和邊肖粮,這個數(shù)量級的數(shù)據(jù)前端瀏覽器的計算力已經(jīng)不足以每次都對數(shù)據(jù)在線布局。因此需要服務(wù)端使用布局算法離線計算節(jié)點位置尔苦,并記錄在Neo4j中涩馆。由于本文的數(shù)據(jù)庫中沒有位置信息行施,因此這一項設(shè)置為true。當本次預(yù)計算完成后凌净,下一次啟動服務(wù)端時可以設(shè)置成false避免再次計算悲龟;
  • visNodeProperty.label:前端可視化節(jié)點顯示的名稱對應(yīng)的字段,這里設(shè)置為數(shù)據(jù)庫中節(jié)點的name字段冰寻;
  • visNodeProperty.value:前端可視化節(jié)點的值對應(yīng)的字段须教。值的大小決定了前端顯示的節(jié)點的實際大小。這里設(shè)置為rate字段斩芭,這樣在前端顯示時轻腺,類似《肖申克的救贖》這樣的高分節(jié)點就會顯示的比較大,而《上海堡壘》這種爛片就會顯示的比較谢浴贬养;
  • visNodeProperty.image:前端可視化節(jié)點的圖片對應(yīng)的字段,這里設(shè)置為數(shù)據(jù)庫節(jié)點中的image字段琴庵;
  • visNodeProperty.x:前端可視化節(jié)點的x坐標對應(yīng)的字段误算,默認為數(shù)據(jù)庫的x字段,因為自動布局算法設(shè)定的就是這個字段所以這里不用更改迷殿,如果數(shù)據(jù)庫本事有位置信息可以自行指定儿礼;
  • visNodeProperty.y: 同上;
  • visNodeProperty.info:前端信息面板的展示代碼庆寺。在本文中設(shè)定和對應(yīng)效果如下:
<p align=center>
#if($prop.image) 
  <img width=150 src="${prop.image}"><br> 
#end 
  <b>${prop.name}</b>
</p>
<p align=left>
  <ul>
    <li>評分:${node.rate}</li>
    <li>類型:${node.category}</li>
    <li>時長:${node.length}分鐘</li>
    <li>語言:${node.language}</li>
  </ul>
</p>
信息面板效果

配置完成后蚊夫,重啟Tomcat。然后瀏覽器打開http://localhost:8080/graphserver/如果能看到字說明服務(wù)端配置成功懦尝。

InteractiveGraph安裝與配置

下載與部署

首先從github下載最新的發(fā)行版:
https://github.com/grapheco/InteractiveGraph/releases
igraph.zip包含InteractiveGraph的js文件知纷,可以結(jié)合項目README的流程自行使用。
本文直接下載了examples.zip中的示例內(nèi)容陵霉,在其上做了適當修改琅轧。
首先在tomcat的webapps目錄中新建igraph文件夾,并將examples.zip中的內(nèi)容解壓到這個文件夾中踊挠。
InteractiveGraph工具包括三個應(yīng)用:

  • GraphNavigator:圖導航器鹰晨,提供對整個圖的全局視圖可視化預(yù)覽;
  • GraphExplorer:圖瀏覽器止毕,通過對某個節(jié)點的展開操作模蜡,逐步瀏覽該節(jié)點和拓展節(jié)點的信息;
  • RelationFinder:關(guān)系查找器扁凛,提供兩個節(jié)點間的關(guān)系路徑發(fā)現(xiàn)忍疾。

上述3個應(yīng)用分別在example1.htmlexample2.htmlexample3.html谨朝。接下來需要修改其中的內(nèi)容卤妒。

修改配置

打開example1.html甥绿,將js中app.loadGson修改為:

igraph.i18n.setLanguage("chs");
var app = new igraph.GraphNavigator(document.getElementById('graphArea'), 'LIGHT');
//修改了這下面↓,上面不要改
app.connect("http://localhost:8080/graphserver/connector-bolt");

這里的localhost:8080為graphserver的地址则披。
同理共缕,對example2.htmlexample3.html也做上述修改。

igraph.i18n.setLanguage("chs");
var app = new igraph.GraphExplorer(document.getElementById('graphArea'));
//修改了這下面↓士复,上面不要改
app.connect("http://localhost:8080/graphserver/connector-bolt");
igraph.i18n.setLanguage("chs");
var app = new igraph.RelFinder(document.getElementById('graphArea'));
//修改了這下面↓图谷,上面不要改                
app.connect("http://localhost:8080/graphserver/connector-bolt");

4.可視化展示

圖導航器

瀏覽器打開http://localhost:8080/igraph/example1.html進入圖導航器可視化界面,如圖:(由于數(shù)據(jù)集中的圖片鏈接現(xiàn)在已被豆瓣更改阱洪,很多節(jié)點的圖片無法顯示)

圖導航器

可以拖動顯示區(qū)域瀏覽全局大圖便贵。

圖瀏覽器

瀏覽器打開http://localhost:8080/igraph/example2.html進入圖瀏覽器可視化界面。
在搜索框中輸入Movie:無間道冗荸,結(jié)果如圖承璃。

搜索結(jié)果

點擊“無間道”,可以看到電影《無間道》對應(yīng)的節(jié)點蚌本。
無間道

在圖瀏覽器中盔粹,單擊節(jié)點可以查看節(jié)點信息,雙擊可以展開節(jié)點程癌。


圖瀏覽器

關(guān)系查找器

瀏覽器打開http://localhost:8080/igraph/example3.html進入關(guān)系查找器可視化界面舷嗡。在右側(cè)輸入起始節(jié)點Person:古天樂和結(jié)束節(jié)點Person:張家輝并選中搜索出的人物,設(shè)定最大路徑長度為4席楚,搜索路徑,結(jié)果如圖所示税稼。共有20條路徑烦秩,點擊右側(cè)路徑列表可以對這條路徑高亮顯示。

關(guān)系查找器

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末郎仆,一起剝皮案震驚了整個濱河市只祠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌扰肌,老刑警劉巖抛寝,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異曙旭,居然都是意外死亡盗舰,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門桂躏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钻趋,“玉大人,你說我怎么就攤上這事剂习÷唬” “怎么了较沪?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長失仁。 經(jīng)常有香客問我尸曼,道長,這世上最難降的妖魔是什么萄焦? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任控轿,我火速辦了婚禮,結(jié)果婚禮上楷扬,老公的妹妹穿的比我還像新娘解幽。我一直安慰自己,他們只是感情好烘苹,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布躲株。 她就那樣靜靜地躺著,像睡著了一般镣衡。 火紅的嫁衣襯著肌膚如雪霜定。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天廊鸥,我揣著相機與錄音望浩,去河邊找鬼。 笑死惰说,一個胖子當著我的面吹牛磨德,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播吆视,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼典挑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了啦吧?” 一聲冷哼從身側(cè)響起您觉,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎授滓,沒想到半個月后琳水,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡般堆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年在孝,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片淮摔。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡浑玛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出噩咪,到底是詐尸還是另有隱情顾彰,我是刑警寧澤极阅,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站涨享,受9級特大地震影響筋搏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜厕隧,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一奔脐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吁讨,春花似錦髓迎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至翎朱,卻和暖如春橄维,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拴曲。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工争舞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人澈灼。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓竞川,卻偏偏與公主長得像,于是被迫代替她去往敵國和親叁熔。 傳聞我的和親對象是個殘疾皇子委乌,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容