知識(shí)圖譜之《海賊王-ONEPICE》領(lǐng)域圖譜項(xiàng)目實(shí)戰(zhàn)(含碼源)
知識(shí)圖譜之《海賊王-ONEPICE》領(lǐng)域圖譜項(xiàng)目實(shí)戰(zhàn)(含碼源):數(shù)據(jù)采集、知識(shí)存儲(chǔ)、知識(shí)抽取、知識(shí)計(jì)算、知識(shí)應(yīng)用、圖譜可視化、問答系統(tǒng)(KBQA)等
實(shí)體關(guān)系可視化頁(yè)面可視化頁(yè)面嘗鮮


1. 項(xiàng)目背景& 項(xiàng)目?jī)?nèi)容
《海賊王》(英文名ONE PIECE) 是由日本漫畫家尾田榮一郎創(chuàng)作的熱血少年漫畫,因?yàn)槠浜甏蟮氖澜缬^、豐富的人物設(shè)定、精彩的故事情節(jié)、草蛇灰線的伏筆,受到世界各地的讀者歡迎,截止2019年11月7日,全球銷量突破4億6000萬本[^1],并被吉尼斯世界紀(jì)錄官方認(rèn)證為“世界上發(fā)行量最高的單一作者創(chuàng)作的系列漫畫”[^2]。
《海賊王》從1997年開始連載至今,以及將近22年,在900多話的漫畫中大量性格鮮明的角色相繼登場(chǎng),故事發(fā)生的地點(diǎn)也在不斷變化,這既給我們帶來閱讀的樂趣,同時(shí)也為我們梳理故事脈絡(luò)帶來了挑戰(zhàn)。
本次任務(wù)試圖為《海賊王》中出現(xiàn)的各個(gè)實(shí)體,包括人物、地點(diǎn)、組織等,構(gòu)建一個(gè)知識(shí)圖譜,幫助我們更好的理解這部作品。
本項(xiàng)目?jī)?nèi)容包括數(shù)據(jù)采集、知識(shí)存儲(chǔ)、知識(shí)抽取、知識(shí)計(jì)算、知識(shí)應(yīng)用五大部分
數(shù)據(jù)采集
本次項(xiàng)目主要采集構(gòu)建了兩個(gè)知識(shí)圖譜和一個(gè)關(guān)系抽取數(shù)據(jù)集
人物知識(shí)圖譜:主要包含各個(gè)人物的信息
關(guān)系抽取數(shù)據(jù)集:標(biāo)注出自然語(yǔ)言中存在的實(shí)體以及他們之間的關(guān)系
實(shí)體關(guān)系知識(shí)圖譜:構(gòu)建《海賊王》中各個(gè)實(shí)體之間關(guān)系的知識(shí)圖譜
知識(shí)存儲(chǔ)
嘗試使用了三元組數(shù)據(jù)庫(kù)Apace Jena和原生圖數(shù)據(jù)庫(kù)Neo4j,并分別使用RDF結(jié)構(gòu)化查詢語(yǔ)言SPARQL和屬性圖查詢語(yǔ)言Cypher,在知識(shí)圖譜上進(jìn)行查詢。
知識(shí)抽取
基于之間構(gòu)建的關(guān)系抽取數(shù)據(jù)集,利用deepke中提供的工具進(jìn)行關(guān)系抽取實(shí)踐,測(cè)試了包括PCNN、GCN、BERT等模型在我們構(gòu)建數(shù)據(jù)集上的效果
知識(shí)計(jì)算
圖計(jì)算:在Neo4j上對(duì)實(shí)體關(guān)系知識(shí)圖譜進(jìn)行了圖挖掘,包括最短路徑查詢、權(quán)威結(jié)點(diǎn)發(fā)現(xiàn)、社區(qū)發(fā)現(xiàn)等
知識(shí)推理:在Apache Jena上對(duì)關(guān)系知識(shí)圖譜進(jìn)行了知識(shí)推理,補(bǔ)全了一部分的數(shù)據(jù)
知識(shí)應(yīng)用
智能問答:基于REfO實(shí)現(xiàn)一個(gè)對(duì)于《海賊王》中人物的知識(shí)庫(kù)問答系統(tǒng)(KBQA)。
可視化圖片:通過D3對(duì)實(shí)體關(guān)系圖片進(jìn)行可視化,并整合了人物知識(shí)圖譜中的信息,進(jìn)行展示。
碼源下載見文末跳轉(zhuǎn)
碼源下載見文末跳轉(zhuǎn)
2.數(shù)據(jù)采集
數(shù)據(jù)來源
本次項(xiàng)目中所使用的數(shù)據(jù)主要來源為兩個(gè):一個(gè)是從別的知識(shí)圖譜中獲取已經(jīng)存在的知識(shí)信息,另一個(gè)是從相關(guān)網(wǎng)頁(yè)中爬取解析半結(jié)構(gòu)化的自然語(yǔ)言文本信息
2.1 人物知識(shí)圖譜構(gòu)建
2.1.1 抽取通用知識(shí)圖譜中已有的目標(biāo)域知識(shí)
知識(shí)圖譜技術(shù)近些年來快速發(fā)展,一些公司機(jī)構(gòu)已經(jīng)構(gòu)建了許多通用知識(shí)圖譜,我們可以從中抽取出我們目標(biāo)領(lǐng)域內(nèi)相關(guān)的實(shí)體知識(shí)信息,作為我們知識(shí)圖譜的冷啟動(dòng)數(shù)據(jù)。
CN-DBpedia[^3]是由復(fù)旦大學(xué)知識(shí)工場(chǎng)[^4]實(shí)驗(yàn)室研發(fā)并維護(hù)的大規(guī)模通用領(lǐng)域結(jié)構(gòu)化百科,我們選擇其作為通用知識(shí)圖譜來源。
整個(gè)處理流程如下:
構(gòu)建《海賊王》實(shí)體詞匯庫(kù)
獲取實(shí)體列表
篩選實(shí)體列表
獲取圖譜中對(duì)應(yīng)實(shí)體的三元組知識(shí)
構(gòu)建《海賊王》實(shí)體詞匯庫(kù)
主要通過領(lǐng)域WiKi獲取《海賊王》中的實(shí)體詞匯庫(kù)。在這里,我們?cè)诿饶锇倏频南嚓P(guān)頁(yè)面[^6]中獲取由粉絲愛好者整理的詞條名信息,作為詞匯庫(kù)。
我們將原始的半結(jié)構(gòu)化詞條數(shù)據(jù)保存在 cndbpedia/data/raw_moegirl_onepiece_entries.txt 中,并利用正則表達(dá)式對(duì)其進(jìn)行解析
python cndbpedia/parse_raw_moegirl_onepiece_entries.py
輸出的結(jié)果保存在 cndbpedia/data/processed_moegirl_onepiece_entries.txt 中,一共提取了509個(gè)詞條名
獲取實(shí)體列表
我們利用知識(shí)工廠提供的API[^5],將詞條名作為輸入實(shí)體指稱項(xiàng)名稱(mention name),獲取返回對(duì)應(yīng)實(shí)體(entity)的列表。
python cndbpedia/get_onepiece_cndbpedia_entities.py
總共獲取了1014個(gè)不同的實(shí)體名,并輸出了兩個(gè)文件,輸出的結(jié)果保存在 cndbpedia/data 文件夾中。
cndbpedia_onepiece_entities_list.txt:保存了所有識(shí)別出的CN-DBpedia中的實(shí)體名,例如
?愛德華·紐蓋特(《航海王燃燒意志》游戲角色)
?愛德華·紐蓋特(日本漫畫《海賊王》中的角色)
?愛莎(《弒神者!》中的弒神者之一)
?愛莎(《海賊王》中的角色)
?愛莎(艾爾之光游戲人物)
moelgirl_cndbpedia_entities_mapping.json :保存著從moegirl的的條目作為實(shí)體指稱項(xiàng)名稱,在api上查找到的對(duì)應(yīng)的實(shí)體列表,例如
?"夏奇": [
? ? ?"夏奇(日本動(dòng)漫《海賊王》角色)",
? ? ?"夏奇(福建人民藝術(shù)劇院主持人)",
? ? ?"夏奇(深圳市夏奇實(shí)業(yè)有限公司)",
? ? ?"夏奇(《永嘉詩(shī)聯(lián)》主編)"
?],
?"布拉曼克": [
? ? ?"布拉曼克"
?],
?"艾佛蘭德拉": [
? ? ?"艾佛蘭德拉"
?],
?"頂上戰(zhàn)爭(zhēng)": [
? ? ?"大事件(漫畫《海賊王》中頂上戰(zhàn)爭(zhēng))"
?],
?"堪十郎": [
? ? ?"堪十郎"
?],
篩選實(shí)體列表
由于自然語(yǔ)言和現(xiàn)實(shí)世界的多義性,往往一個(gè)mention name可能對(duì)應(yīng)著知識(shí)圖譜中的多個(gè)不同實(shí)體。就拿 布魯克 這個(gè)名字來說,在api返回的實(shí)體列表中,就有好多不同的實(shí)體
布魯克
布魯克(奧地利城市穆爾河畔布魯克縮寫)
布魯克(廣告策劃師)
布魯克(日本動(dòng)漫《海賊王》中的人物)
布魯克(溫力銘演唱歌曲)
布魯克(游戲《賽爾號(hào)》中的精靈)
布魯克(西班牙2010年拍攝電影)
而其中第四個(gè)才是我們需要的。
因此我們可以設(shè)置一些篩選條件,只有當(dāng)實(shí)體名中包含:海賊王,航海王,海賊,航海,onepiece,one piece,動(dòng)漫,漫畫 這些關(guān)鍵詞之一時(shí),才認(rèn)為是我們需要的實(shí)體
python cndbpedia/filter_moelgirl_cndbpedia_entities_mapping_file.py
輸出的結(jié)果保存在 cndbpedia/data 文件夾中
篩選結(jié)果:在509個(gè)詞條中
有162個(gè)詞條在CN-DBpedia沒有對(duì)應(yīng)的實(shí)體名,這些詞條被保存在 moelgirl_cndbpedia_api_no_results_mention_name_list.txt;
有11個(gè)詞條雖然有實(shí)體名,但所有對(duì)應(yīng)實(shí)體名中都沒有包含上面提到的關(guān)鍵詞,這些詞條被保存在 filter_out_entities_mapping.json
剩余336個(gè)詞條中,都有對(duì)應(yīng)符合條件的實(shí)體名,一共有357個(gè)。這些詞條被保存在 query_avpair_entities_list.txt,此外 query_avpair_entities_mapping.json 中保存著這些合法詞條名和實(shí)體名對(duì)應(yīng)的字典。
獲取圖譜中對(duì)應(yīng)實(shí)體的三元組知識(shí)
我們利用知識(shí)工廠提供的API[^5],根據(jù)前面篩選的實(shí)例列表,獲取圖譜中對(duì)應(yīng)實(shí)體的三元組知識(shí)
python cndbpedia/get_onepiece_cndbpedia_avpair.py
輸出結(jié)果保存在 cndbpedia/data 文件夾中
query_avpair_cndbpedia_onepiece_results.json:保存著每個(gè)實(shí)體對(duì)應(yīng)的三元組知識(shí)的字典,采用兩級(jí)索引結(jié)構(gòu),第一級(jí)索引是mention name,第二級(jí)索引是實(shí)體名字,示例如下
?"砂糖": {
? ? ? ? ?"砂糖(《海賊王》人物)": {
? ? ? ? ? ? ?"性別": "女",
? ? ? ? ? ? ?"配音": "詹雅菁(臺(tái)灣)",
? ? ? ? ? ? ?"中文名": "砂糖",
? ? ? ? ? ? ?"登場(chǎng)作品": "海賊王",
? ? ? ? ? ? ?"初次登場(chǎng)": "漫畫第682話、動(dòng)畫608話",
? ? ? ? ? ? ?"惡魔果實(shí)": "超人系童趣果實(shí)",
? ? ? ? ? ? ?"職位": "唐吉訶德家族梅花軍特別干部",
? ? ? ? ? ? ?"外文名稱": "Sugar",
? ? ? ? ? ? ?"年齡": "外貌年齡10歲,真實(shí)年齡22歲",
? ? ? ? ? ? ?"CATEGORY_ZH": "人物",
? ? ? ? ? ? ?"DESC": "砂糖是日本動(dòng)漫《海賊王》中的人物,童趣果實(shí)能力者。唐吉訶德家族干部,隸屬梅花軍托雷波爾。被家族視為重要的干部,多弗朗明哥為此特別安排家族最高干部托雷波爾擔(dān)任她的貼身保鏢。"
? ? ? ? ?}
? ? ?},
query_avpair_keys_list_file.txt:保存在所有屬性名稱的列表
2.1.2 抽取網(wǎng)頁(yè)中半結(jié)構(gòu)化的知識(shí)
生命卡(vivre card)[^7]是海賊王官方整理發(fā)布的角色資料圖鑒,包含著豐富的角色信息。國(guó)內(nèi)的粉絲愛好者也將其翻譯成了中文版本,并發(fā)布在了網(wǎng)頁(yè)上[^8]。這部分就是希望抽取Talkop論壇中相關(guān)網(wǎng)頁(yè)中存在的半結(jié)構(gòu)化信息,構(gòu)建對(duì)應(yīng)人物的知識(shí)圖譜。
抽取流程
由于格式較為固定,因此采用模板匹配的方式來抽取知識(shí),整個(gè)流程如下:
從網(wǎng)頁(yè)中獲取原始文本信息
人工刪除不相關(guān)的文本
利用代碼以模板匹配的方式,自動(dòng)抽取人物屬性信息
? cd talkop
? python parse_processed_manual_talkop_vivre_card.py
輸出的文件保存在 talkop/data/processed_manual_talkop_vivre_card 文件夾中,每個(gè)網(wǎng)頁(yè)對(duì)應(yīng)著三個(gè)輸出文件
xxx-predicate_key_list.txt:所有解析得到的predicate
xxx-entities_id_name_list.txt:所有解析得到的id和實(shí)體名
xxx-entities_avpair.json:抽取到所有實(shí)體的屬性知識(shí),以json的格式保存
人工校驗(yàn):例如:查看是否抽取到了所有的實(shí)體、通過查看抽取的predicate結(jié)果來調(diào)整模板。整個(gè)過程中是代碼自動(dòng)抽取和人工校驗(yàn)構(gòu)成閉環(huán)的過程,在閉環(huán)過程中不斷補(bǔ)充模板信息,改善抽取結(jié)果
在整個(gè)過程中,2、3、4是不斷循環(huán)往復(fù)的過程,直至抽取的知識(shí)滿足我們的需要。
匯總結(jié)果
在上面部分中,我們分別抽取了各個(gè)網(wǎng)頁(yè)中人物實(shí)體的屬性信息,現(xiàn)在將這些信息進(jìn)行進(jìn)一步的匯總
cd talkop
python summary_talkop_vivre_card.py
從匯總的結(jié)果可以看到,一共包含660個(gè)不同的實(shí)體,164個(gè)不同的predicate
輸出的文件保存在 talkop/data/processed_manual_talkop_vivre_card 文件夾中,一共有兩個(gè)文件:
summary_predicate_set.txt:所有predicate的匯總
summary_entities_id_name_list.txt:所有抽取得到的實(shí)體名以及對(duì)應(yīng)ID的匯總
2.2. 關(guān)系抽取數(shù)據(jù)集構(gòu)建
標(biāo)注數(shù)據(jù)來源:在前面構(gòu)建的人物知識(shí)圖譜中,有一項(xiàng)重要的屬性是歷史信息,記錄著每個(gè)人物在故事中的時(shí)間線以及對(duì)應(yīng)的故事。每個(gè)人的歷史信息記錄著其與其他實(shí)體之間交互的信息,我們可以利用它來構(gòu)建我們垂直領(lǐng)域內(nèi)的關(guān)系抽取數(shù)據(jù)集
標(biāo)注工具:精靈標(biāo)注助手[^8]
構(gòu)建方法:自底向上構(gòu)建,在構(gòu)建過程中逐步構(gòu)建整個(gè)圖譜的schema
數(shù)據(jù)標(biāo)注格式:精靈標(biāo)注助手提供導(dǎo)出json格式,其具體形式如下所示,其中 T 和 E 分別表示標(biāo)注出的實(shí)體信息和關(guān)系信息
?{
? ? ?"content": "xxxx"
? ? ?"labeled": true,
? ? ?"outputs": {
? ? ? ? ?"annotation": {
? ? ? ? ? ? ?"A": [""],
? ? ? ? ? ? ?"E": [""],
? ? ? ? ? ? ?"R": ["",{
? ? ? ? ? ? ? ? ? ? ?"arg1": "Arg1",
? ? ? ? ? ? ? ? ? ? ?"arg2": "Arg2",
? ? ? ? ? ? ? ? ? ? ?"from": 1,
? ? ? ? ? ? ? ? ? ? ?"name": "到過",
? ? ? ? ? ? ? ? ? ? ?"to": 2
? ? ? ? ? ? ? ? ?},
? ? ? ? ? ? ?],
? ? ? ? ? ? ?"T": ["",{
? ? ? ? ? ? ? ? ? ? ?"attributes": [],
? ? ? ? ? ? ? ? ? ? ?"end": 7,
? ? ? ? ? ? ? ? ? ? ?"id": 1,
? ? ? ? ? ? ? ? ? ? ?"name": "人",
? ? ? ? ? ? ? ? ? ? ?"start": 0,
? ? ? ? ? ? ? ? ? ? ?"type": "T",
? ? ? ? ? ? ? ? ? ? ?"value": "蒙其·D·路飛"
? ? ? ? ? ? ? ? ?},
? ? ? ? ? ? ?]
? ? ? ? ?}
? ? ?},
? ? ?"path": "D:\\annot\\fuseki_vivrecard_sentence_item.txt",
? ? ?"time_labeled": 1578072175246
?}
數(shù)據(jù)存儲(chǔ)位置: 被標(biāo)注的原始數(shù)據(jù)被保存在 deepke-master/data/vivrecard/rawfuseki_vivrecard_sentence_item.txt原始標(biāo)注結(jié)果被保存在 deepke-master/data/vivrecard/annot/outputs/fuseki_vivrecard_sentence_item.json。
為了方便后續(xù)關(guān)系抽取模型處理,我們將標(biāo)注數(shù)據(jù)轉(zhuǎn)為符合deepke項(xiàng)目格式的數(shù)據(jù)
并保存在 deepke-master/data/vivrecard/origin,具體詳情參見知識(shí)抽取部分
2.3 數(shù)據(jù)集統(tǒng)計(jì)信息
實(shí)體類型:一共7種實(shí)體:'事件', '組織', '船只', '地點(diǎn)', '職務(wù)', '惡魔果實(shí)', '人'
關(guān)系類型:一共22種關(guān)系
?
這些關(guān)系的頻數(shù)柱狀圖如下圖所示,可以看到這些關(guān)系展現(xiàn)出明顯的長(zhǎng)尾分布
?
訓(xùn)練正樣本個(gè)數(shù):616個(gè)
2.4 實(shí)體關(guān)系知識(shí)圖譜構(gòu)建
在進(jìn)行關(guān)系抽取數(shù)據(jù)集的標(biāo)注過程中,我們將標(biāo)注的實(shí)體和關(guān)系單獨(dú)導(dǎo)出,構(gòu)建《海賊王》實(shí)體關(guān)系數(shù)據(jù)集
在上述過程中,一共標(biāo)注了307個(gè)不同的實(shí)體,569個(gè)不同結(jié)點(diǎn)間的關(guān)系
cd deepke-master
python utils/convert_vivrecard2deepke.py
輸出的實(shí)體關(guān)系數(shù)據(jù)保存在 deepke-master/data/vivrecard/summary/vizdata_vivrecard_relation.json,可用于后續(xù)進(jìn)行知識(shí)圖譜可視化,具體參見知識(shí)圖譜可視化部分
3. 知識(shí)存儲(chǔ)
3.1. 基于RDF 三元組數(shù)據(jù)庫(kù):Apache Jena
3.1.1 Jena 簡(jiǎn)介&項(xiàng)目實(shí)踐
Jena[^9]是 Apache 頂級(jí)項(xiàng)目,其前身為惠普實(shí)驗(yàn)室開發(fā)的 Jena 工具包.Jena 是語(yǔ)義 Web 領(lǐng)域主要的開源框 架和 RDF 三元組庫(kù),較好地遵循了 W3C 標(biāo)準(zhǔn),其功能包括:RDF 數(shù)據(jù)管理、RDFS 和 OWL 本體管理、SPARQL 查詢處理等.Jena 具備一套原生存儲(chǔ)引擎,可對(duì) RDF 三元組進(jìn)行基于磁盤或內(nèi)存的存儲(chǔ)管理.同時(shí),具有一套基 于規(guī)則的推理引擎,用以執(zhí)行 RDFS 和 OWL 本體推理任務(wù).
avpair to triple
以vivrecard人物屬性知識(shí)圖譜為例,首先我們將之前獲得的數(shù)據(jù),轉(zhuǎn)換為Jena支持解析的 N-Triple 三元組格式,命名空間前綴為 <http://kg.course/talkop-vivre-card/>
cd talkop
python avpair2ntriples_talkop_vivre_card.py
導(dǎo)出的 N-Triple 格式的數(shù)據(jù)保存在 talkop/data/processed_manual_talkop_vivre_card/ntriples_talkop_vivre_card.nt,一共有14055個(gè),其中非空triples有12863個(gè)
NOTE:
在項(xiàng)目構(gòu)建過程中,我們也將從CN-DBpedia獲取的知識(shí)轉(zhuǎn)換為 N-Triple 格式,命名空間前綴為 <http://kg.course/onepiece/>
? python cndbpedia/avpair2ntriples_onepiece_cndbpedia.py
結(jié)果保存在 cndbpedia/data/ntriples_cndbpedia_onepiece.nt,一共有4691個(gè)triple
啟動(dòng) Fuseki
按照陳華均老師提供文件:https://github.com/zjunlp/kg-course/blob/master/tutorials/Tutorial-Jena.pdf
進(jìn)一步配置fuseki,上傳數(shù)據(jù)集就可以查詢了
3.1.2 SPARQL查詢示例
SPARQL[^11] 是 W3C 制定的 RDF 知識(shí)圖譜標(biāo)準(zhǔn)查詢語(yǔ)言.SPARQL 從語(yǔ)法上借鑒了 SQL.SPARQL 查詢的 基本單元是三元組模式(triple pattern),多個(gè)三元組模式可構(gòu)成基本圖模式(basic graph pattern).SPARQL 支持多 種運(yùn)算符,將基本圖模式擴(kuò)展為復(fù)雜圖模式(complex graph pattern).SPARQL 1.1 版本引入了屬性路徑(property path)機(jī)制以支持 RDF 圖上的導(dǎo)航式查詢.下面使用圖 2 所示的電影知識(shí)圖譜 RDF 圖,通過示例介紹 SPARQL 語(yǔ)言的基本功能. [^10]
下面給出了使用SPARQL在我們構(gòu)建的數(shù)據(jù)庫(kù)上進(jìn)行查詢的示例
查詢前五個(gè)角色的身高
? PREFIX : <http://kg.course/talkop-vivre-card/>
? select ?s ?name ?zhname ?height ?o where {
? ? ? ?s ?height ?o .
? ? ? FILTER(?height in (:身高, :身長(zhǎng))) .
? ? ? OPTIONAL { ?s :名稱 ?name. ?s :外文名 ?zhname.}
? }
? limit 5
結(jié)果
? ?"s" , "name" , "zhname" , "height" , "o" ,
? ?":0001" , "【蒙其·D·路飛/Monkey D Luffy】" , "Monkey D Luffy" , ":身高" , "174cm" ,
? ?":0004" , "【烏索普/Usopp】" , "Usopp" , ":身高" , "174cm" ,
? ?":0511" , "【喬艾莉·波妮/Jewelry Bonney】" , "Jewelry Bonney" , ":身高" , "174cm" ,
? ?":0002" , "【羅羅諾亞·索隆/Roronoa Zoro】" , "Roronoa Zoro" , ":身高" , "181cm" ,
? ?":0224" , "【緹娜/Hina】" , "Hina" , ":身高" , "181cm" ,
篩選生日范圍
? PREFIX : <http://kg.course/talkop-vivre-card/>
? select ?s ?name ?o where {
? ? ? ?s :生日 ?o .
? ? ? ?s :名稱 ?name .
? ? ? ? filter(?o > '4月1日' && ?o < '5月1日')
? }
? limit 5
結(jié)果
? ?"s" , "name" , "o" ,
? ?":0009" , "【布魯克/Brook】" , "4月3日" ,
? ?":0660" , "【伯爾杰米/Porchemy】" , "4月3日" ,
? ?":0010" , "【甚平/Jinbe】" , "4月2日" ,
? ?":0076" , "【哲夫/Zeff】" , "4月2日" ,
? ?":0028" , "【克比/Koby】" , "5月13日" ,
3.2. 基于原生圖數(shù)據(jù)庫(kù):Neo4j
3.2.1. Neo4j簡(jiǎn)介&Cypher查詢示例
Neo4j[^12]是由 Neo 技術(shù)公司開發(fā)的圖數(shù)據(jù)庫(kù).可以說,Neo4j 是目前流行程度最高的圖數(shù)據(jù)庫(kù)產(chǎn)品.Neo4j 基 于屬性圖模型,其存儲(chǔ)管理層為屬性圖的節(jié)點(diǎn)、節(jié)點(diǎn)屬性、邊、邊屬性等元素設(shè)計(jì)了專門的存儲(chǔ)方案.這使得 Neo4j 在存儲(chǔ)層對(duì)于圖數(shù)據(jù)的存取效率優(yōu)于關(guān)系數(shù)據(jù)庫(kù).
4.2.2. 項(xiàng)目實(shí)踐
relation to triple
以實(shí)體關(guān)系知識(shí)圖譜為例,首先我們將之前獲得的各個(gè)實(shí)體之間關(guān)系的數(shù)據(jù),轉(zhuǎn)換為Jena支持解析的 N-Triple 三元組格式,命名空間前綴為 <http://kg.course/talkop-vivre-card/deepke/>
cd deepke-master
python utils/convert_vivrecard2deepke.py
導(dǎo)出的 N-Triple 格式的數(shù)據(jù)保存在 deepke-master/data/vivrecard/summary/vivrecard_ntriples.nt,一共有1848個(gè)
啟用 Neo4j
Neo4j的下載安裝可以參考: https://neo4j.com/download-thanks-desktop/?edition=desktop&flavour=winstall64&release=1.2.4&offline=true
cd D:\neo4j\bin
neo4j.bat console
之后訪問:http://localhost:7474/ 就可以了
默認(rèn)的用戶名和密碼都是 neo4j
Cypher 最初是圖數(shù)據(jù)庫(kù) Neo4j 中實(shí)現(xiàn)的屬性圖數(shù)據(jù)查詢語(yǔ)言,是一種聲明式的語(yǔ)言,用戶只需要聲明查什么,而不需要關(guān)系怎么查。
下面給出了使用Cypher在我們構(gòu)建的數(shù)據(jù)庫(kù)上進(jìn)行查詢的示例
導(dǎo)入
? CREATE INDEX ON :Resource(uri)
? CALL semantics.importRDF("file:///${PROJECT_PATH}/deepke-master/data/vivrecard/summary/vivrecard_ntriples.nt","N-Triples")
查看schema
? call db.schema()
把resource屏蔽掉,就能清楚的看到schema了

查詢前100個(gè)人
? MATCH (n:ns0__人) RETURN n LIMIT 100

查詢屬于人的結(jié)點(diǎn)中,URI里面包含 薇薇 的結(jié)點(diǎn)
? MATCH (n:ns0__人)
? WHERE n.uri CONTAINS '薇薇'
? RETURN n.uri
?
根據(jù)uri篩選名字間最短路徑
? MATCH p=shortestPath(
? (n1)-[*]-(n2)
? )
? WHERE n1.uri CONTAINS '斯摩格' and n2.uri CONTAINS '羅賓'
? RETURN p

根據(jù)名字篩選德雷斯羅薩到司法島里面四跳的路徑
? # 五跳內(nèi)能到的所有路徑
? # 9312 多蘿菲(Miss.圣誕快樂)
? # 9306 本·貝克曼
? MATCH p = ((n1)-[*4]-(n2))
? WHERE n1.uri CONTAINS '司法島' and n2.uri CONTAINS '德雷斯羅薩'
? RETURN p
可以發(fā)現(xiàn)這里面存在一些環(huán)路的情況,即同一個(gè)結(jié)點(diǎn)在路徑中出現(xiàn)兩次

4. 知識(shí)抽取
DeepKE[^13]基于 Pytorch 的深度學(xué)習(xí)中文關(guān)系抽取處理套件。在這部分中我們利用之前構(gòu)建的關(guān)系抽取數(shù)據(jù)集和deepke,進(jìn)行中文關(guān)系抽取實(shí)踐
4.1. 數(shù)據(jù)轉(zhuǎn)換&標(biāo)注統(tǒng)計(jì)
在這部分,我們需要完成以下三部分內(nèi)容:
將我們的標(biāo)注結(jié)果轉(zhuǎn)換為deepke所接收的格式
為了保證關(guān)系分布均勻,將數(shù)據(jù)隨機(jī)打亂
完成訓(xùn)練集、測(cè)試集、驗(yàn)證集的劃分,目前按 7:2:1進(jìn)行劃分
使用 deepke-master/utils/convert_vivrecard2deepke.py 完成數(shù)據(jù)格式轉(zhuǎn)換
cd deepke-master
python utils/convert_vivrecard2deepke.py
輸出
一共有616個(gè)訓(xùn)練正樣本,其中train、test、valid分別有:431/123/62個(gè)
輸出的文件保存在 deepke-master/data/vivrecard/ 中的 origin 和 summary 文件夾中
├── annot
│ └── outputs
│ ? ? └── formatted_fuseki_vivrecard_sentence_item.json # 對(duì)json文件進(jìn)行縮進(jìn)等格式化
├── origin ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?# 輸出轉(zhuǎn)換得到deepke訓(xùn)練數(shù)據(jù)到該文件夾
│ ├── relation.csv
│ ├── test.csv
│ ├── train.csv
│ └── valid.csv
└── summary
? ?├── all_sent.txt ? ? ? ? ? ? ? ? ? ? ?# 所有的句子
? ?├── annot_entity_sent.txt ? ? ? ? ? ? # 被標(biāo)記上實(shí)體的句子
? ?├── annot_relation_sent.txt ? ? ? ? ? # 被標(biāo)記上關(guān)系的句子
? ?├── entities_type_name_dict.json ? ? ?# 標(biāo)注數(shù)據(jù)中所有的實(shí)體類型,以及屬于該類型的所有實(shí)體名字
? ?├── relation.csv ? ? ? ? ? ? ? ? ? ? ?# 標(biāo)注數(shù)據(jù)中的存在的所有數(shù)據(jù)
? ?├── unannot_entity_sent.txt ? ? ? ? ? # [未被]標(biāo)記上實(shí)體的句子
? ?└── unannot_relation_sent.txt ? ? ? ? # [未被]標(biāo)記上關(guān)系的句子
4.2. 訓(xùn)練
在訓(xùn)練過程中我們嘗試使用了deepke所提供的PCNN, rnn, gcn, capsule, transformer, bert 這些模型,epoch 設(shè)置為 50,num_relations 根據(jù)我們數(shù)據(jù)集的實(shí)際情況修改為19,需要注意的是基于BERT的語(yǔ)言模型進(jìn)行訓(xùn)練時(shí),需要先在相關(guān)網(wǎng)頁(yè)[^14]下載好預(yù)訓(xùn)練模型
新的數(shù)據(jù)集有22種關(guān)系(包括None),需要通過 num_relations 來更改
cd deepke-master
python main.py show_plot=False data_path=data/vivrecard/origin out_path=data/vivrecard/out num_relations=22 epoch=50 model=cnn
python main.py show_plot=False data_path=data/vivrecard/origin out_path=data/vivrecard/out num_relations=22 epoch=50 model=rnn
python main.py show_plot=False data_path=data/vivrecard/origin out_path=data/vivrecard/out num_relations=22 epoch=50 model=gcn
python main.py show_plot=False data_path=data/vivrecard/origin out_path=data/vivrecard/out num_relations=22 epoch=50 model=capsule
python main.py show_plot=False data_path=data/vivrecard/origin out_path=data/vivrecard/out num_relations=22 epoch=50 model=transformer
# lm bert layer=1
python main.py show_plot=False data_path=data/vivrecard/origin out_path=data/vivrecard/out num_relations=22 epoch=50 model=lm lm_file=~/ZJU_study/Knowledge_Graph/deepke/pretrained/ num_hidden_layers=1
# lm bert layer=2
python main.py show_plot=False data_path=data/vivrecard/origin out_path=data/vivrecard/out num_relations=22 epoch=50 model=lm lm_file=~/ZJU_study/Knowledge_Graph/deepke/pretrained/ gpu_id=0 num_hidden_layers=2
# lm bert layer=3
python main.py show_plot=False data_path=data/vivrecard/origin out_path=data/vivrecard/out num_relations=22 epoch=50 model=lm lm_file=/home/zenghao/ZJU_study/Knowledge_Graph/deepke/pretrained/ gpu_id=1 num_hidden_layers=3
4.3. 訓(xùn)練結(jié)果
?
可以到基于bert的語(yǔ)言模型效果最好,明顯由于其他模型。GCN的效果最差。這也說明在小規(guī)模數(shù)據(jù)上利用預(yù)訓(xùn)練的語(yǔ)言模型還是能夠抽取到比較好的特征的。
但是在我們后面對(duì)于實(shí)際數(shù)據(jù)的預(yù)測(cè)結(jié)果發(fā)現(xiàn),語(yǔ)言模型的泛化效果似乎不如PCNN模型的好
我們猜測(cè)是由于我們的數(shù)據(jù)存在長(zhǎng)尾分布問題,模型可能趨向于預(yù)測(cè)某些特定關(guān)系來作弊,已達(dá)到準(zhǔn)確率提高的效果
5. 知識(shí)計(jì)算
5.1. 圖計(jì)算
知識(shí)圖譜的一個(gè)很重要的特征就是其的圖結(jié)構(gòu),不同實(shí)體之間的結(jié)構(gòu)本身就內(nèi)含著許多的隱式的信息,可以被進(jìn)一步的挖掘利用。
在這部分中,我們參考他人在類似領(lǐng)域的實(shí)踐[^15][^16],利用Neo4j提供的圖算法,對(duì)我們構(gòu)建的實(shí)體關(guān)系知識(shí)圖譜,用圖算法進(jìn)行一定的計(jì)算分析,包括計(jì)算最短路徑、關(guān)鍵結(jié)點(diǎn)、結(jié)點(diǎn)中心度、社區(qū)發(fā)現(xiàn)等。
5.1.1. 人物網(wǎng)絡(luò)分析
人物數(shù)量
萬事以簡(jiǎn)單開始。先看看上圖上由有多少人物:
MATCH (c:`ns0__人`) RETURN count(c)
| count(c) | | :------: | | 134 |
概要統(tǒng)計(jì)
統(tǒng)計(jì)每個(gè)角色接觸的其它角色的數(shù)目:
MATCH (c:`ns0__人`)-[]->(:`ns0__人`)
WITH c, count(*) AS num
RETURN min(num) AS min, max(num) AS max, avg(num) AS avg_characters, stdev(num) AS stdev
| min | max | avg_characters | stdev | | :--- | :--- | :----------------- | :----------------- | | 1 | 6 | 1.8374999999999997 | 1.1522542572790615 |
圖(網(wǎng)絡(luò))的直徑
網(wǎng)絡(luò)的直徑或者測(cè)底線或者最長(zhǎng)最短路徑:
// Find maximum diameter of network
// maximum shortest path between two nodes
MATCH (a:`ns0__人`), (b:`ns0__人`) WHERE id(a) > id(b)
MATCH p=shortestPath((a)-[*]-(b))
RETURN length(p) AS len, extract(x IN nodes(p) | split(x.uri, 'http://kg.course/talkop-vivre-card/deepke')[-1]) AS path
ORDER BY len DESC LIMIT 4
?
最短路徑
使用Cypher 的shortestPath函數(shù)找到圖中任意兩個(gè)角色之間的最短路徑。讓我們找出克洛克達(dá)爾和加爾帝諾(Mr.3)之間的最短路徑:
MATCH p=shortestPath(
(n1)-[*]-(n2)
)
WHERE n1.uri CONTAINS '克洛克達(dá)爾' and n2.uri CONTAINS '加爾帝諾'
RETURN p
還可以對(duì)路徑中的結(jié)點(diǎn)進(jìn)行一些限制,例如路徑中不能包含某種類型的結(jié)點(diǎn)
MATCH p=shortestPath((n1)-[*]-(n2))
WHERE n1.uri CONTAINS '克洛克達(dá)爾' and n2.uri CONTAINS '加爾帝諾' and id(n2) > id(n1) and NONE(n IN nodes(p) WHERE n:`ns0__組織`)
RETURN p
路徑中只能包含某種類型的結(jié)點(diǎn)
例子:所有從索隆到強(qiáng)尼的1到3跳的路徑中,只經(jīng)過人物結(jié)點(diǎn)的路徑
MATCH p=(n1)-[*1..3]-(n2)
WHERE n1.uri CONTAINS '索隆' and n2.uri CONTAINS '強(qiáng)尼' and all(x in nodes(p) where 'ns0__人' IN LABELS(x))
RETURN p
所有最短路徑
聯(lián)結(jié)斯摩格和一本松之間的最短路徑可能還有其它路徑,我們可以使用Cypher的allShortestPaths函數(shù)來查找:
MATCH (n1:`ns0__人`), (n2:`ns0__人`) WHERE n1.uri CONTAINS '克洛克達(dá)爾' and n2.uri CONTAINS '加爾帝諾' and id(n2) > id(n1)
MATCH p=allShortestPaths((n1)-[*]-(n2))
RETURN p
5.1.2. 關(guān)鍵節(jié)點(diǎn)
在網(wǎng)絡(luò)中,如果一個(gè)節(jié)點(diǎn)位于其它兩個(gè)節(jié)點(diǎn)所有的最短路徑上,即稱為關(guān)鍵節(jié)點(diǎn)。下面我們找出網(wǎng)絡(luò)中所有的關(guān)鍵節(jié)點(diǎn):
// Find all pivotal nodes in network
MATCH (a:`ns0__人`), (b:`ns0__人`) WHERE id(a) > id(b)
MATCH p=allShortestPaths((a)-[*]-(b)) WITH collect(p) AS paths, a, b
MATCH (c:`ns0__人`) WHERE all(x IN paths WHERE c IN nodes(x)) AND NOT c IN [a,b]
RETURN a.uri, b.uri, c.uri AS PivotalNode SKIP 490 LIMIT 10
?
從結(jié)果表格中我們可以看出有趣的結(jié)果:娜美和路飛是薩奇斯和諾琪高的關(guān)鍵節(jié)點(diǎn)。這意味著,所有聯(lián)結(jié)薩奇斯和諾琪高的最短路徑都要經(jīng)過娜美和路飛。我們可以通過可視化薩奇斯和諾琪高之間的所有最短路徑來驗(yàn)證:
MATCH (n1:`ns0__人`), (n2:`ns0__人`) WHERE n1.uri CONTAINS '薩奇斯' and n2.uri CONTAINS '諾琪高' and id(n1) <> id(n2)
MATCH p=shortestPath((n1)-[*]-(n2))
RETURN p
5.1.3. 節(jié)點(diǎn)中心度
節(jié)點(diǎn)中心度給出網(wǎng)絡(luò)中節(jié)點(diǎn)的重要性的相對(duì)度量。有許多不同的方式來度量中心度,每種方式都代表不同類型的“重要性”。
度中心性(Degree Centrality)
度中心性是最簡(jiǎn)單度量,即為某個(gè)節(jié)點(diǎn)在網(wǎng)絡(luò)中的聯(lián)結(jié)數(shù)。在《海賊王》的圖中,某個(gè)角色的度中心性是指該角色接觸的其他角色數(shù)。作者使用Cypher計(jì)算度中心性:
MATCH (c:`ns0__人`)-[]-()
RETURN split(c.uri, 'http://kg.course/talkop-vivre-card/deepke')[-1] AS character, count(*) AS degree ORDER BY degree DESC
?
從上面可以發(fā)現(xiàn),在《海賊王》網(wǎng)絡(luò)中路飛和最多的角色有接觸。鑒于他是漫畫的主角,我們覺得這是有道理的。
介數(shù)中心性(Betweenness Centrality)
介數(shù)中心性:在網(wǎng)絡(luò)中,一個(gè)節(jié)點(diǎn)的介數(shù)中心性是指其它兩個(gè)節(jié)點(diǎn)的所有最短路徑都經(jīng)過這個(gè)節(jié)點(diǎn),則這些所有最短路徑數(shù)即為此節(jié)點(diǎn)的介數(shù)中心性。介數(shù)中心性是一種重要的度量,因?yàn)樗梢澡b別出網(wǎng)絡(luò)中的“信息中間人”或者網(wǎng)絡(luò)聚類后的聯(lián)結(jié)點(diǎn)。

圖中紅色節(jié)點(diǎn)是具有高的介數(shù)中心性,網(wǎng)絡(luò)聚類的聯(lián)結(jié)點(diǎn)。
為了計(jì)算介數(shù)中心性,需要安裝 algo 庫(kù)
CALL algo.betweenness.stream('ns0__人', 'ns1__遇見',{direction:'both'})
YIELD nodeId, centrality
MATCH (user:`ns0__人`) WHERE id(user) = nodeId
RETURN user.uri AS user,centrality
ORDER BY centrality DESC;
或者
CALL algo.betweenness.stream('ns0__人', null,{direction:'both'})
YIELD nodeId, centrality
MATCH (user:`ns0__人`) WHERE id(user) = nodeId
RETURN user.uri AS user,centrality
ORDER BY centrality DESC;
?
NOTE:上面的是不考慮方向的,所以設(shè)置為 {direction:'both'}。如果考慮方向,可以
loading incoming relationships: 'INCOMING','IN','I' or '<'loading outgoing relationships: 'OUTGOING','OUT','O' or '>'
緊度中心性(Closeness centrality)
緊度中心性是指到網(wǎng)絡(luò)中所有其他角色的平均距離的倒數(shù)。在圖中,具有高緊度中心性的節(jié)點(diǎn)在聚類社區(qū)之間被高度聯(lián)結(jié),但在社區(qū)之外不一定是高度聯(lián)結(jié)的。

網(wǎng)絡(luò)中具有高緊度中心性的節(jié)點(diǎn)被其它節(jié)點(diǎn)高度聯(lián)結(jié)
MATCH (c:`ns0__人`)
WITH collect(c) AS characters
CALL algo.closeness.stream('ns0__人', null)
YIELD nodeId, centrality
RETURN algo.asNode(nodeId).uri AS node, centrality
ORDER BY centrality DESC
LIMIT 20;
?
5.1.4. 社區(qū)發(fā)現(xiàn)
CALL algo.beta.louvain.stream(null, null, {
graph: 'huge',
direction: 'BOTH'
}) YIELD nodeId, community, communities
RETURN algo.asNode(nodeId).uri as name, community, communities
ORDER BY community ASC
?
可以看到,基本把瓦波爾那一系列的community給檢測(cè)出來了,包括在磁鼓島和黑暗磁鼓王國(guó)
5.1.5. PageRank
CALL algo.pageRank.stream('ns0__人', null, {iterations:20, dampingFactor:0.85})
YIELD nodeId, score
RETURN algo.asNode(nodeId).uri AS page,score
ORDER BY score DESC
?
5.2. 知識(shí)推理
TODO
6. 知識(shí)應(yīng)用
6.1. 智能問答
在這部分中我們參考前人的工作[^17][^18],基于REfO[^19]實(shí)現(xiàn)了一個(gè)KBQA系統(tǒng),主要流程為:解析輸入的自然語(yǔ)言問句生成 SPARQL 查詢,進(jìn)一步請(qǐng)求后臺(tái)基于 TDB 知識(shí)庫(kù)的 Apache Jena Fuseki 服務(wù), 得到結(jié)果。代碼和數(shù)據(jù)存放在 vivirecard-KB_query 目錄下
6.1.1. 支持的問題類型
對(duì)于生日/英文名/血型/星座/霸氣/身高的查詢
誰出生在哪里/出生在某個(gè)地方的有誰
6.1.2. 查詢示例
運(yùn)行 python query_main.py 就可以開始進(jìn)行QA過程
cd vivirecard-KB_query
python query_main.py
直接輸入問題,按回車后就會(huì)返回答案;當(dāng)系統(tǒng)中沒有對(duì)應(yīng)知識(shí)時(shí),會(huì)返回 I don't know. :(;當(dāng)系統(tǒng)無法理解問題時(shí)會(huì)返回 I can't understand. :(
雷利的身高是多少?
188cm
羅杰的血型是啥
S型
誰出生在風(fēng)車村?
蒙其·D·路飛、瑪琪諾、喬路叔&雞嬸、烏普·斯拉普
出生在可可亞西村的有誰?
娜美、諾琪高、阿健、貝爾梅爾、Dr.納克、薩姆
我想知道斯摩格的生日
3月14日
特朗普的生日是多少
I don't know. :(
sasdasdasd
I can't understand. :(
6.2. 知識(shí)圖譜可視化
在這部分中,我們參考別人的工作[^20],利用D3[^21]對(duì)之前構(gòu)建的實(shí)體關(guān)系知識(shí)圖譜提供可視化交互功能,包括結(jié)點(diǎn)連接關(guān)系可視化、查詢相關(guān)結(jié)點(diǎn)信息。同時(shí)在這部分也整合了之間構(gòu)建的人物屬性知識(shí)圖譜,提供了信息框的展示過程,相關(guān)的數(shù)據(jù)和代碼存放在 visualization 目錄下。整個(gè)可視化頁(yè)面的交互過程如下面的[gif圖]
可視化網(wǎng)頁(yè)存放于 visualization/html/index.html,可以通過 Microsoft Edge 瀏覽器直接打開
如果需要在其他瀏覽器中打開,可能會(huì)加載不出來可視化結(jié)果。這是因?yàn)榭缬蛘?qǐng)求在大多數(shù)瀏覽器中是禁止的,請(qǐng)求不到j(luò)son數(shù)據(jù)。因此需要用 WAMP/LAMP/MAMP 配置一個(gè)Web網(wǎng)絡(luò)環(huán)境。
打開后可視化界面如下所示,不同的顏色代表不同類型的實(shí)體,具有關(guān)系的實(shí)體會(huì)用白色的細(xì)線連接,可以明顯的看到有些實(shí)體與其他實(shí)體存在大量的連接

點(diǎn)擊左上角的模式切換按鈕,我們可以把結(jié)點(diǎn)展示從圓圈模式變換為文本模式,能夠進(jìn)行更加細(xì)致的觀察

選中某個(gè)結(jié)點(diǎn)后,將只會(huì)顯示該節(jié)點(diǎn)以及與其直接相連接的結(jié)點(diǎn)。特別的,如果該節(jié)點(diǎn)類型是人物,還會(huì)在頁(yè)面右側(cè)顯示該人物的信息框

此外左側(cè)還提供了搜索框的功能,可以方便我們查找結(jié)點(diǎn)信息
碼源下載見文末跳轉(zhuǎn)
碼源下載見文末跳轉(zhuǎn):(https://blog.csdn.net/sinat_39620217/article/details/131587267)
更多優(yōu)質(zhì)內(nèi)容請(qǐng)關(guān)注公號(hào)&知乎:汀丶人工智能;會(huì)提供一些相關(guān)的資源和優(yōu)質(zhì)文章,免費(fèi)獲取閱讀。
?