Datawhale Notes | 知識圖譜介紹與Neo4J實戰
0. 定義
知識圖譜本質上是語義網路(Semantic Network)的知識庫
==>從實際應用的角度出發,可以簡單地把知識圖譜理解成多關係圖(Multi-relational Graph)
圖
圖(Graph)是由節點(Vertex)和邊(Edge)來構成,多關係圖一般包含多種型別的節點和多種型別的邊。實體(節點)指的是現實世界中的事物比如人、地名、概念、藥物、公司等,關係(邊)則用來表達不同實體之間的某種聯絡,比如人-“居住在”-北京、張三和李四是“朋友”、邏輯迴歸是深度學習的“先導知識”等等。
Schema
限定待加入知識圖譜資料的格式;相當於某個領域內的資料模型
- 作用:規範結構化資料的表達,一條資料必須滿足Schema預先定義好的實體物件及其型別,才被允許更新到知識圖譜中
- 例:
- 圖中的DataType限定了知識圖譜節點值的型別為文字、日期、數字(浮點型與整型)
- 圖中的Thing限定了節點的型別及其屬性(即圖1-1中的邊)
-
- ==> 基於該Schema構建的知識圖譜中僅可含作品、地方組織、人物;其中作品的屬性為電影與音樂、地方組織的屬性為當地的商業(eg:飯店、俱樂部等)、人物的屬性為歌手
1. 資料來源
- 業務本身的資料。這部分資料通常包含在公司內的資料庫表並以結構化的方式儲存,一般只需要簡單預處理即可以作為後續AI系統的輸入;
- 網路上公開、抓取的資料。(難點)這些資料通常是以網頁的形式存在所以是非結構化的資料,一般需要藉助於自然語言處理等技術來提取出結構化資訊。例如:
Bill Gates和Malinda Gate的關係就可以從非結構化資料中提煉出來,比如維基百科等資料來源。
左邊是一段非結構化的英文文字,右邊是從這些文字中抽取出來的實體和關係。
2. 相關技術
在構建類似的圖譜過程當中,主要涉及以下幾個方面的自然語言處理技術:
2.1 實體命名識別(NER, Name Entity Recognition)
- 目標:從文本里提取出實體並對每個實體做分類/打標籤;
- 舉例:下述示例圖文本里,提取出實體-“NYC”,標記實體型別為 “Location”;同理,提取出“Virgil's BBQ”,標記實體型別為“Restarant”。
2.2 關係抽取(RE, Relation Extraction)
- 目標:通過關係抽取技術,把實體間的關係從文字中提取出來;
- 舉例:實體“hotel”和“Hilton property”之間的關係為“in”;“hotel”和“Time Square”的關係為“near”。
2.3 實體統一(ER, Entity Resolution)
- 目標:有些實體寫法上不一樣,實際指向同一個實體 ==> 減少實體的種類,降低圖譜的稀疏性(Sparsity);
- 舉例:“NYC”和“New York”表面上是不同的字串,實際指的都是紐約這個城市,需要合併。
2.4 指代消解(Coreference Resolution)
- 目標:確認文字中出現的“it”, “he”, “she”等代詞的確切實體指向,在下述圖例中,兩個被標記出來的“it”都指向“hotel”這個實體。
3. 知識圖譜的儲存
主要有兩種儲存方式:
- 基於RDF的儲存;
- 基於圖資料庫的儲存。
RDF重點在資料的易釋出以及共享,儲存三元組,無屬性;圖資料庫則把重點放在了高效的圖查詢和搜尋,包含屬性。
對於RDF的儲存系統,Jena或許一個比較不錯的選擇。
對於圖資料庫,Neo4J系統目前仍是使用率最高的圖資料庫,它擁有活躍的社群,系統本身的查詢效率高,唯一的不足是不支援準分散式。
OrientDB和JanusGraph(原Titan)支援分散式,但這些系統相對較新,社群不如Neo4j活躍。
Neo4J實戰
參考上述教程的實踐筆記:
Neo4J分為社群版和企業版,企業版在橫向擴充套件、許可權控制、執行效能、HA等方面都比社群版好,適合正式的生產環境,普通的學習和開發採用免費社群版就好。
1. 首先,我們刪除資料庫中以往的圖,確保一個空白的環境進行操作:
MATCH (n) DETACH DELETE n
這裡,MATCH
是匹配操作,而小括號()代表一個節點node(可理解為括號類似一個圓形),括號裡面的n為識別符號。
2. 接著,我們建立一個人物節點:
CREATE (n:Person {name:'John'}) RETURN n
CREATE
是建立操作,Person
是標籤,代表節點的型別。花括號{}代表節點的屬性,屬性類似Python的字典。這條語句的含義就是建立一個標籤為Person的節點,該節點具有一個name屬性,屬性值是John。
3. 我們繼續來建立更多的人物節點,並分別命名:
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
如圖所示,6個人物節點建立成功
4. 接下來建立地區節點
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'})
可以看到,節點型別為Location,屬性包括city和state。
如圖所示,共有6個人物節點、5個地區節點,Neo4J貼心地使用不用的顏色來表示不同型別的節點。
5. 接下來建立關係
MATCH (a:Person {name:'Liz'}),
(b:Person {name:'Mike'})
MERGE (a)-[:FRIENDS]->(b)
這裡的方括號[]
即為關係,FRIENDS
為關係的型別。注意這裡的箭頭-->
是有方向的,表示是從a到b的關係。 如圖,Liz和Mike之間建立了FRIENDS
關係,通過Neo4J的視覺化很明顯的可以看出:
6. 關係也可以增加屬性
MATCH (a:Person {name:'Shawn'}),
(b:Person {name:'Sally'})
MERGE (a)-[:FRIENDS {since:2001}]->(b)
在關係中,同樣的使用花括號{}來增加關係的屬性,也是類似Python的字典,這裡給FRIENDS關係增加了since屬性,屬性值為2001,表示他們建立朋友關係的時間。
7. 接下來增加更多的關係
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)
如圖,人物關係圖已建立好,有點圖譜的意思了吧?[有呀!]
8. 然後,我們需要建立不同型別節點之間的關係-人物和地點的關係
MATCH (a:Person {name:'John'}), (b:Location {city:'Boston'}) MERGE (a)-[:BORN_IN {year:1978}]->(b)
這裡的關係是BORN_IN,表示出生地,同樣有一個屬性,表示出生年份。
如圖,在人物節點和地區節點之間,人物出生地關係已建立好。
9. 同樣建立更多人的出生地
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)
建好以後,整個圖如下
10. 至此,知識圖譜的資料已經插入完畢,可以開始做查詢了。我們查詢下所有在Boston出生的人物
MATCH (a:Person)-[:BORN_IN]->(b:Location {city:'Boston'}) RETURN a,b
結果如圖
11. 查詢所有對外有關係的節點
MATCH (a)-->() RETURN a
注意這裡箭頭的方向,返回結果不含任何地區節點,因為地區並沒有指向其他節點(只是被指向)
12. 查詢所有有關係的節點
MATCH (a)--() RETURN a
結果如圖
13. 查詢所有對外有關係的節點,以及關係型別
MATCH (a)-[r]->() RETURN a.name, type(r)
結果如圖
14. 查詢所有有結婚關係的節點
MATCH (n)-[:MARRIED]-() RETURN n
結果如圖
15. 建立節點的時候就建好關係
CREATE (a:Person {name:'Todd'})-[r:FRIENDS]->(b:Person {name:'Carlos'})
結果如圖
16. 查詢某人的朋友的朋友
MATCH (a:Person {name:'Mike'})-[r1:FRIENDS]-()-[r2:FRIENDS]-(friend_of_a_friend) RETURN friend_of_a_friend.name AS fofName
返回Mike的朋友的朋友:
17. 增加/修改節點的屬性
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表示修改
操作
18. 刪除節點的屬性
MATCH (a:Person {name:'Mike'}) SET a.test='test'
MATCH (a:Person {name:'Mike'}) REMOVE a.test
刪除屬性操作主要通過REMOVE
19. 刪除節點
MATCH (a:Location {city:'Portland'}) DELETE a
刪除節點操作是DELETE
20. 刪除有關係的節點
MATCH (a:Person {name:'Todd'})-[rel]-(b:Person) DELETE a,b,rel