參考datawhale開源組織:https://github.com/datawhalechina/team-learning-nlp/blob/master/KnowledgeGraph_Basic/task01.md
一蠢甲、知識圖譜簡介
后期會一直更新遇到的坑勇吊,關于mac的會在后期更入
1.1 引言
從一開始的Google搜索汉规,到現(xiàn)在的聊天機器人礼殊、大數(shù)據(jù)風控、證券投資针史、智能醫(yī)療晶伦、自適應教育、推薦系統(tǒng)啄枕,無一不跟知識圖譜相關婚陪。它在技術領域的熱度也在逐年上升。
早在 2010 年微軟就開始構建知識圖譜攘残,包括 Satori 和 Probase;2012 年从绘,Google 正式發(fā)布了 Google Knowledge Graph驻债,現(xiàn)在規(guī)模已超 700 億翩伪。目前微軟和 Google 擁有全世界最大的通用知識圖譜逻炊,F(xiàn)acebook 擁有全世界最大的社交知識圖譜威根,而阿里巴巴和亞馬遜則分別構建了商品知識圖譜。
本章以通俗易懂的方式來講解知識圖譜相關的知識谭梗、介紹從零開始搭建知識圖譜過程當中需要經(jīng)歷的步驟以及每個階段。本次組隊學習還將動手實踐一個關于kg在智能問答中的應用随抠。
1.2 什么是知識圖譜呢盅抚?
知識圖譜是由 Google 公司在 2012 年提出來的一個新的概念壤巷。從學術的角度,我們可以對知識圖譜給一個這樣的定義:“知識圖譜本質上是語義網(wǎng)絡(Semantic Network)的知識庫”譬胎。但這有點抽象堰乔,所以換個角度,從實際應用的角度出發(fā)其實可以簡單地把知識圖譜理解成多關系圖(Multi-relational Graph)需忿。
1.2.1 什么是圖(Graph)呢痹扇?
圖(Graph)是由節(jié)點(Vertex)和邊(Edge)來構成,多關系圖一般包含多種類型的節(jié)點和多種類型的邊斩祭。實體(節(jié)點)指的是現(xiàn)實世界中的事物比如人劣像、地名、概念摧玫、藥物耳奕、公司等,關系(邊)則用來表達不同實體之間的某種聯(lián)系诬像,比如人-“居住在”-北京屋群、張三和李四是“朋友”、邏輯回歸是深度學習的“先導知識”等等颅停。
1.2.2 什么是 Schema 呢谓晌?
知識圖譜另外一個很重要的概念是 Schema:
介紹:限定待加入知識圖譜數(shù)據(jù)的格式;相當于某個領域內(nèi)的數(shù)據(jù)模型癞揉,包含了該領域內(nèi)有意義的概念類型以及這些類型的屬性
作用:規(guī)范結構化數(shù)據(jù)的表達纸肉,一條數(shù)據(jù)必須滿足Schema預先定義好的實體對象及其類型,才被允許更新到知識圖譜中喊熟, 一圖勝千言
圖中的DataType限定了知識圖譜節(jié)點值的類型為文本柏肪、日期、數(shù)字(浮點型與整型)
圖中的Thing限定了節(jié)點的類型及其屬性(即圖1-1中的邊)
舉例說明:基于下圖Schema構建的知識圖譜中僅可含作品芥牌、地方組織烦味、人物;其中作品的屬性為電影與音樂壁拉、地方組織的屬性為當?shù)氐纳虡I(yè)(eg:飯店谬俄、俱樂部等)、人物的屬性為歌手
tips:本次組隊學習不涉及schema的構建
1.3 知識圖譜的價值在哪呢弃理?
從圖5中可以看出溃论,知識圖譜是人工智能很重要的一個分支, 人工智能的目標為了讓機器具備像人一樣理性思考及做事的能力 -> 在符號主義的引領下,知識工程(核心內(nèi)容即建設專家系統(tǒng))取得了突破性的進展 -> 在整個知識工程的分支下痘昌,知識表示是一個非常重要的任務 -> 而知識圖譜又恰恰是知識表示的重要一環(huán)
二钥勋、怎么構建知識圖譜呢炬转?
2.1 知識圖譜的數(shù)據(jù)來源于哪里?
知識圖譜的構建是后續(xù)應用的基礎算灸,而且構建的前提是需要把數(shù)據(jù)從不同的數(shù)據(jù)源中抽取出來扼劈。對于垂直領域的知識圖譜來說,它們的數(shù)據(jù)源主要來自兩種渠道:
- 第一種:業(yè)務本身的數(shù)據(jù)菲驴。這部分數(shù)據(jù)通常包含在公司內(nèi)的數(shù)據(jù)庫表并以結構化的方式存儲荐吵,一般只需要簡單預處理即可以作為后續(xù)AI系統(tǒng)的輸入;
-
第二種:網(wǎng)絡上公開谢翎、抓取的數(shù)據(jù)捍靠。這些數(shù)據(jù)通常是以網(wǎng)頁的形式存在所以是非結構化的數(shù)據(jù),一般需要借助于自然語言處理等技術來提取出結構化信息森逮。
比如在下面的搜索例子里,Bill Gates和Malinda Gate的關系就可以從非結構化數(shù)據(jù)中提煉出來磁携,比如維基百科等數(shù)據(jù)源褒侧。
2.2 信息抽取的難點在哪里?
信息抽取的難點在于處理非結構化數(shù)據(jù)谊迄。在下面的圖中闷供,我們給出了一個實例。左邊是一段非結構化的英文文本统诺,右邊是從這些文本中抽取出來的實體和關系歪脏。
2.3 構建知識圖譜所涉及的技術?
在構建類似的圖譜過程當中粮呢,主要涉及以下幾個方面的自然語言處理技術:
實體命名識別(Name Entity Recognition)
關系抽刃鍪А(Relation Extraction)
實體統(tǒng)一(Entity Resolution)
指代消解(Coreference Resolution)
2.4、知識圖譜的具體構建技術是什么啄寡?
下面針對每一項技術解決的問題做簡單的描述豪硅,至于這些是具體怎么實現(xiàn)的,不在這里一一展開挺物,后續(xù)課程和知識圖譜第二期的課程將會慢慢展開:
2.4.1 實體命名識別(Named Entity Recognition)
- 實體命名識別(英語:Named Entity Recognition)懒浮,簡稱NER
- 目標:就是從文本里提取出實體并對每個實體做分類/打標簽;
- 舉例說明:比如從上述文本里识藤,我們可以提取出實體-“NYC”砚著,并標記實體類型為 “Location”;我們也可以從中提取出“Virgil's BBQ”痴昧,并標記實體類型為“Restarant”稽穆。
- 這種過程稱之為實體命名識別,這是一項相對比較成熟的技術剪个,有一些現(xiàn)成的工具可以用來做這件事情秧骑。
2.4.2 關系抽劝嫒贰(Relation Extraction)
- 關系抽取(英語:Relation Extraction)乎折,簡稱 RE
- 介紹:通過關系抽取技術绒疗,把實體間的關系從文本中提取出來;
- 舉例說明:比如實體“hotel”和“Hilton property”之間的關系為“in”骂澄;“hotel”和“Time Square”的關系為“near”等等吓蘑。
2.4.3 實體統(tǒng)一(Entity Resolution)
- 實體統(tǒng)一(英語:Entity Resolution),簡稱 ER
- 介紹:對于有些實體寫法上不一樣坟冲,但其實是指向同一個實體磨镶;
- 舉例說明:比如“NYC”和“New York”表面上是不同的字符串,但其實指的都是紐約這個城市健提,需要合并琳猫。
- 價值:實體統(tǒng)一不僅可以減少實體的種類,也可以降低圖譜的稀疏性(Sparsity)私痹;
2.4.4 指代消解(Disambiguation)
- 指代消解(英語:Disambiguation)
-
介紹:文本中出現(xiàn)的“it”, “he”, “she”這些詞到底指向哪個實體脐嫂,比如在本文里兩個被標記出來的“it”都指向“hotel”這個實體。
-
三紊遵、知識圖譜的存儲
知識圖譜主要有兩種存儲方式:
一種是基于RDF的存儲账千;
另一種是基于圖數(shù)據(jù)庫的存儲。
它們之間的區(qū)別如下圖所示暗膜。RDF一個重要的設計原則是數(shù)據(jù)的易發(fā)布以及共享匀奏,圖數(shù)據(jù)庫則把重點放在了高效的圖查詢和搜索上。其次学搜,RDF以三元組的方式來存儲數(shù)據(jù)而且不包含屬性信息娃善,但圖數(shù)據(jù)庫一般以屬性圖為基本的表示形式,所以實體和關系可以包含屬性恒水,這就意味著更容易表達現(xiàn)實的業(yè)務場景会放。其中Neo4j系統(tǒng)目前仍是使用率最高的圖數(shù)據(jù)庫,它擁有活躍的社區(qū)钉凌,而且系統(tǒng)本身的查詢效率高咧最,但唯一的不足就是不支持準分布式。相反御雕,OrientDB和JanusGraph(原Titan)支持分布式矢沿,但這些系統(tǒng)相對較新,社區(qū)不如Neo4j活躍酸纲,這也就意味著使用過程當中不可避免地會遇到一些刺手的問題捣鲸。如果選擇使用RDF的存儲系統(tǒng),Jena或許一個比較不錯的選擇闽坡。
四栽惶、Neo4J 介紹與安裝
4.1 引言
“工欲善其事愁溜,必先利其器”,知識圖譜作為一種特殊的圖結構外厂,自然需要專門的圖數(shù)據(jù)庫進行存儲冕象。
知識圖譜由于其數(shù)據(jù)包含實體、屬性汁蝶、關系等渐扮,常見的關系型數(shù)據(jù)庫諸如MySQL之類不能很好的體現(xiàn)數(shù)據(jù)的這些特點,因此知識圖譜數(shù)據(jù)的存儲一般是采用圖數(shù)據(jù)庫(Graph Databases)掖棉。而Neo4j是其中最為常見的圖數(shù)據(jù)庫墓律。
4.2 Neo4J 下載
首先在 Neo4J官網(wǎng) 下載 Neo4J。
- Neo4J分為社區(qū)版和企業(yè)版:
- 企業(yè)版:收費幔亥,在橫向擴展耻讽、權限控制、運行性能紫谷、HA等方面都比社區(qū)版好齐饮,適合正式的生產(chǎn)環(huán)境;
- 社區(qū)版:免費笤昨,普通的學習和開發(fā)采用免費社區(qū)版就好。
4.3 Neo4J 安裝
- 在Mac或者Linux中握恳,安裝好jdk后瞒窒,直接解壓下載好的Neo4J包,運行命令
bin/neo4j start
- windows系統(tǒng)下載好neo4j和jdk 1.8.0后乡洼,輸入以下命令啟動后neo4j
neo4j.bat console
4.4 Neo4J Web 界面 介紹
Neo4J提供了一個用戶友好的 Web 界面崇裁,可以進行各項配置、寫入束昵、查詢等操作拔稳,并且提供了可視化功能。類似ElasticSearch一樣锹雏,我個人非常喜歡這種開箱即用的設計巴比。
打開瀏覽器,輸入http://127.0.0.1:7474/browser/礁遵,如下圖 13 所示轻绞,界面最上方就是交互的輸入框。
記錄一下windows安裝的坑:
如果conf文件把這句話注釋掉佣耐,就會出現(xiàn)身份未驗證政勃,客戶端未授權的bug,所以不能注釋掉兼砖。
4.5 Cypher查詢語言
Cypher:
介紹:是Neo4J的聲明式圖形查詢語言奸远,允許用戶不必編寫圖形結構的遍歷代碼既棺,就可以對圖形數(shù)據(jù)進行高效的查詢。
設計目的:類似SQL懒叛,適合于開發(fā)者以及在數(shù)據(jù)庫上做點對點模式(ad-hoc)查詢的專業(yè)操作人員丸冕。
其具備的能力包括:
創(chuàng)建、更新芍瑞、刪除節(jié)點和關系
通過模式匹配來查詢和修改節(jié)點和關系 - 管理索引和約束等
五晨仑、Neo4J 實戰(zhàn)
5.1 引言
這個案例的節(jié)點主要包括人物和城市兩類,人物和人物之間有朋友拆檬、夫妻等關系洪己,人物和城市之間有出生地的關系。特別鳴謝知乎@異塵手把手教你快速入門知識圖譜 - Neo4J教程
- Person-Friends-PERSON
- Person-Married-PERSON
- Person-Born_in-Location
5.2 創(chuàng)建節(jié)點
-
刪除數(shù)據(jù)庫中以往的圖竟贯,確保一個空白的環(huán)境進行操作【注:慎用答捕,如果庫內(nèi)有重要信息的話】:
MATCH (n) DETACH DELETE n
這里,MATCH是匹配操作屑那,而小括號()代表一個節(jié)點node(可理解為括號類似一個圓形)拱镐,括號里面的n為標識符。
創(chuàng)建一個人物節(jié)點:
CREATE (n:Person {name:'John'}) RETURN n
注:
CREATE是創(chuàng)建操作持际,Person是標簽沃琅,代表節(jié)點的類型。
花括號{}代表節(jié)點的屬性蜘欲,屬性類似Python的字典益眉。
這條語句的含義就是創(chuàng)建一個標簽為Person的節(jié)點,該節(jié)點具有一個name屬性姥份,屬性值是John郭脂。
創(chuàng)建更多的人物節(jié)點,并分別命名:
CREATE (n:Person {name:'Sally'}) RETURN n
CREATE (n:Person {name:'Steve'}) RETURN n
CREATE (n:Person {name:'Mike'}) RETURN n
CREATE (n:Person {name:'Liz'}) RETURN n
CREATE (n:Person {name:'Shawn'}) RETURN n
如圖 15 所示澈歉,6個人物節(jié)點創(chuàng)建成功
創(chuàng)建地區(qū)節(jié)點
CREATE (n:Location {city:'Miami', state:'FL'})
CREATE (n:Location {city:'Boston', state:'MA'})
CREATE (n:Location {city:'Lynn', state:'MA'})
CREATE (n:Location {city:'Portland', state:'ME'})
CREATE (n:Location {city:'San Francisco', state:'CA'})
可以看到展鸡,節(jié)點類型為Location,屬性包括city和state埃难。
如圖 16 所示莹弊,共有6個人物節(jié)點、5個地區(qū)節(jié)點凯砍,Neo4J貼心地使用不用的顏色來表示不同類型的節(jié)點箱硕。
5.3 創(chuàng)建關系
朋友關系
MATCH (a:Person {name:'Liz'}),
(b:Person {name:'Mike'})
MERGE (a)-[:FRIENDS]->(b)
注:
方括號[]即為關系,F(xiàn)RIENDS為關系的類型悟衩。
注意這里的箭頭-->是有方向的剧罩,表示是從a到b的關系。 這樣座泳,Liz和Mike之間建立了FRIENDS關系惠昔。
關系增加屬性
MATCH (a:Person {name:'Shawn'}),
(b:Person {name:'Sally'})
MERGE (a)-[:FRIENDS {since:2001}]->(b)
增加更多的朋友關系:
MATCH (a:Person {name:'Shawn'}), (b:Person {name:'John'}) MERGE (a)-[:FRIENDS {since:2012}]->(b)
MATCH (a:Person {name:'Mike'}), (b:Person {name:'Shawn'}) MERGE (a)-[:FRIENDS {since:2006}]->(b)
MATCH (a:Person {name:'Sally'}), (b:Person {name:'Steve'}) MERGE (a)-[:FRIENDS {since:2006}]->(b)
MATCH (a:Person {name:'Liz'}), (b:Person {name:'John'}) MERGE (a)-[:MARRIED {since:1998}]->(b)
這樣幕与,圖譜就已經(jīng)建立好了:
5.4 創(chuàng)建 出生地關系
建立不同類型節(jié)點之間的關系-人物和地點的關系
MATCH (a:Person {name:'John'}), (b:Location {city:'Boston'}) MERGE (a)-[:BORN_IN {year:1978}]->(b)
MATCH (a:Person {name:'Liz'}), (b:Location {city:'Boston'}) MERGE (a)-[:BORN_IN {year:1981}]->(b)
MATCH (a:Person {name:'Mike'}), (b:Location {city:'San Francisco'}) MERGE (a)-[:BORN_IN {year:1960}]->(b)
MATCH (a:Person {name:'Shawn'}), (b:Location {city:'Miami'}) MERGE (a)-[:BORN_IN {year:1960}]->(b)
MATCH (a:Person {name:'Steve'}), (b:Location {city:'Lynn'}) MERGE (a)-[:BORN_IN {year:1970}]->(b)
這里的關系是BORN_IN,表示出生地镇防,同樣有一個屬性啦鸣,表示出生年份。
如圖 18 来氧,在人物節(jié)點和地區(qū)節(jié)點之間诫给,人物出生地關系已建立好。
創(chuàng)建節(jié)點的時候就建好關系
CREATE (a:Person {name:'Todd'})-[r:FRIENDS]->(b:Person{name:'Carlos'})
最終該圖譜如下圖所示:
5.5 圖數(shù)據(jù)庫查詢
查詢下所有在Boston出生的人物
MATCH (a:Person)-[:BORN_IN]->(b:Location {city:'Boston'}) RETURN a,b
結果如圖 19:
查詢所有對外有關系的節(jié)點
MATCH (a)--() RETURN a
結果如圖 20:
查詢所有有關系的節(jié)點
MATCH (a)-[r]->() RETURN a.name, type(r)
結果如圖21:
查詢所有對外有關系的節(jié)點啦扬,以及關系類型
MATCH (a)-[r]->() RETURN a.name, type(r)
結果如圖22:
查詢所有有結婚關系的節(jié)點
MATCH (n)-[:MARRIED]-() RETURN n
結果如圖 23:
查找某人的朋友的朋友
MATCH (a:Person {name:'Mike'})-[r1:FRIENDS]-()-[r2:FRIENDS]-(friend_of_a_friend) RETURN friend_of_a_friend.name AS fofName
返回Mike的朋友的朋友中狂,結果如圖 24:
5.6 刪除和修改
增加/修改節(jié)點的屬性
MATCH (a:Person {name:'Liz'}) SET a.age=34
MATCH (a:Person {name:'Shawn'}) SET a.age=32
MATCH (a:Person {name:'John'}) SET a.age=44
MATCH (a:Person {name:'Mike'}) SET a.age=25
這里,SET表示修改操作
刪除節(jié)點的屬性
MATCH (a:Person {name:'Mike'}) SET a.test='test'
MATCH (a:Person {name:'Mike'}) REMOVE a.test
刪除屬性操作主要通過REMOVE 3. 刪除節(jié)點
MATCH (a:Location {city:'Portland'}) DELETE a
刪除節(jié)點操作是DELETE 4. 刪除有關系的節(jié)點
MATCH (a:Person {name:'Todd'})-[rel]-(b:Person) DELETE a,b,rel
六扑毡、通過 Python 操作 Neo4j
6.1 neo4j模塊:執(zhí)行CQL ( cypher ) 語句
# step 1:導入 Neo4j 驅動包
from neo4j import GraphDatabase
# step 2:連接 Neo4j 圖數(shù)據(jù)庫
driver = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", "password"))
# 添加 關系 函數(shù)
def add_friend(tx, name, friend_name):
tx.run("MERGE (a:Person {name: $name}) "
"MERGE (a)-[:KNOWS]->(friend:Person {name: $friend_name})",
name=name, friend_name=friend_name)
# 定義 關系函數(shù)
def print_friends(tx, name):
for record in tx.run("MATCH (a:Person)-[:KNOWS]->(friend) WHERE a.name = $name "
"RETURN friend.name ORDER BY friend.name", name=name):
print(record["friend.name"])
# step 3:運行
with driver.session() as session:
session.write_transaction(add_friend, "Arthur", "Guinevere")
session.write_transaction(add_friend, "Arthur", "Lancelot")
session.write_transaction(add_friend, "Arthur", "Merlin")
session.read_transaction(print_friends, "Arthur")
上述程序的核心部分胃榕,抽象一下就是:
neo4j.GraphDatabase.driver(xxxx).session().write_transaction(函數(shù)(含tx.run(CQL語句)))
或者
neo4j.GraphDatabase.driver(xxxx).session().begin_transaction.run(CQL語句)
6.2 py2neo模塊:通過操作python變量,達到操作neo4j的目的
# step 1:導包
from py2neo import Graph, Node, Relationship
# step 2:構建圖
g = Graph()
# step 3:創(chuàng)建節(jié)點
tx = g.begin()
a = Node("Person", name="Alice")
tx.create(a)
b = Node("Person", name="Bob")
# step 4:創(chuàng)建邊
ab = Relationship(a, "KNOWS", b)
# step 5:運行
tx.create(ab)
tx.commit()
py2neo模塊符合python的習慣瞄摊,寫著感覺順暢勋又,其實可以完全不會CQL也能寫
七、通過csv文件批量導入圖數(shù)據(jù)
前面學習的是單個創(chuàng)建節(jié)點换帜,不適合大批量導入楔壤。這里我們介紹使用neo4j-admin import命令導入,適合部署在docker環(huán)境下的neo4j惯驼。 其他導入方法也可以參考Neo4j之導入數(shù)據(jù)
csv分為兩個nodes.csv和relations.csv挺邀,注意關系里的起始節(jié)點必須是在nodes.csv里能找到的:
# nodes.csv需要指定唯一ID和nam,
headers = [
'unique_id:ID', # 圖數(shù)據(jù)庫中節(jié)點存儲的唯一標識
'name', # 節(jié)點展示的名稱
'node_type:LABEL', # 節(jié)點的類型,比如Person和Location
'property' # 節(jié)點的其他屬性
]
# relations.csv
headers = [
'unique_id', # 圖數(shù)據(jù)庫中關系存儲的唯一標識
'begin_node_id:START_ID', # begin_node和end_node的值來自于nodes.csv中節(jié)點
'end_node_id:END_ID',
'begin_node_name',
'end_node_name',
'begin_node_type',
'end_node_type',
'relation_type:TYPE', # 關系的類型跳座,比如Friends和Married
'property' # 關系的其他屬性
]
制作出兩個csv后,通過以下步驟導入neo4j:
兩個文件nodes.csv 泣矛,relas.csv放在
neo4j安裝絕對路徑/import
導入到圖數(shù)據(jù)庫mygraph.db
neo4j bin/neo4j-admin import --nodes=/var/lib/neo4j/import/nodes.csv --relationships=/var/lib/neo4j/import/relas.csv --delimiter=^ --database=mygraph.db
delimiter=^ 指的是csv的分隔符
指定neo4j使用哪個數(shù)據(jù)庫
修改 /root/neo4j/conf/neo4j.conf 文件中的 dbms.default_database=mygraph.db
重啟neo4j就可以看到數(shù)據(jù)已經(jīng)導入成功了
導入csv的坑:
正確導入方法疲眷,按照教程把一些keys寫入csv里(表格形式)
nodes.csv:
relation.csv:
然后填入一些數(shù)據(jù),注意start_id和end_id一定要和關聯(lián)的第一張表的主鍵聯(lián)系起來您朽,第一個是start_id,最后一個是end_id.
如果要把數(shù)據(jù)庫改成自己的狂丝,那么就需要把配置文件conf中的active_database改成自己的數(shù)據(jù)庫,這樣才會在你的界面中顯示出來:
dbms.active_database=mygraph.db
dbms.default_database=mygraph.db