1. 程式人生 > 實用技巧 >Datawhale Notes | 知識圖譜介紹與Neo4J實戰

Datawhale Notes | 知識圖譜介紹與Neo4J實戰

[github]

0. 定義

知識圖譜本質上是語義網路(Semantic Network)的知識庫

==>從實際應用的角度出發,可以簡單地把知識圖譜理解成多關係圖(Multi-relational Graph)

圖(Graph)是由節點(Vertex)和邊(Edge)來構成,多關係圖一般包含多種型別的節點和多種型別的邊。實體(節點)指的是現實世界中的事物比如人、地名、概念、藥物、公司等,關係(邊)則用來表達不同實體之間的某種聯絡,比如人-“居住在”-北京、張三和李四是“朋友”、邏輯迴歸是深度學習的“先導知識”等等。

Schema

限定待加入知識圖譜資料的格式;相當於某個領域內的資料模型

,包含了該領域內有意義的概念型別以及這些型別的屬性

  • 作用:規範結構化資料的表達,一條資料必須滿足Schema預先定義好的實體物件及其型別,才被允許更新到知識圖譜中
  • 例:
    • 圖中的DataType限定了知識圖譜節點值的型別為文字、日期、數字(浮點型與整型)
    • 圖中的Thing限定了節點的型別及其屬性(即圖1-1中的邊)
    • ==> 基於該Schema構建的知識圖譜中僅可含作品、地方組織、人物;其中作品的屬性為電影與音樂、地方組織的屬性為當地的商業(eg:飯店、俱樂部等)、人物的屬性為歌手

1. 資料來源

  1. 業務本身的資料。這部分資料通常包含在公司內的資料庫表並以結構化的方式儲存,一般只需要簡單預處理即可以作為後續AI系統的輸入;
  2. 網路上公開、抓取的資料。(難點)這些資料通常是以網頁的形式存在所以是非結構化的資料,一般需要藉助於自然語言處理等技術來提取出結構化資訊。例如:

    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