項目實戰:如何構建知識圖譜

實踐了下怎麼建一個簡單的知識圖譜,兩個版本,一個從 0 開始(start from scratch),一個在 CN-DBpedia 基礎上補充,把 MySQL,PostgreSQL,Neo4j 數據庫都嘗試了下。本身跌跌撞撞摸索可能踩坑了都不知道,歡迎討論。node

1. CN-DBpedia 構建流程mysql

知識庫能夠分爲兩種類型,一種是以 Freebase,Yago2 爲表明的 Curated KBs,主要從維基百科和 WordNet 等知識庫中抽取大量的實體及實體關係,像是一種結構化的維基百科。另外一種是以 Stanford OpenIE,和咱們學校 Never-Ending Language Learning (NELL) 爲表明的 Extracted KBs,直接從上億個非結構化網頁中抽取實體關係三元組。redis

與 Freebase 相比,這樣獲得的知識更加多樣性,但同時精確度要低於 Curated KBs,由於實體關係和實體更多的是天然語言的形式,如「奧巴馬出生在火奴魯魯。」 能夠被表示爲(「Obama」, 「was also born in」, 「 Honolulu」)。sql

下面以 CN-DBpedia 爲例看下知識圖譜大體是怎麼構建的。數據庫

 

上圖分別是 CN-DBpedia 的構建流程和系統架構。知識圖譜的構建是一個浩大的工程,從大方面來說,分爲知識獲取、知識融合、知識驗證、知識計算和應用幾個部分,也就是上面架構圖從下往上走的一個流程,簡單來走一下這個流程。json

2. 數據支持層網絡

最底下是知識獲取及存儲,或者說是數據支持層,首先從不一樣來源、不一樣結構的數據中獲取知識,CN-DBpedia 的知識來源主要是經過爬取各類百科知識這類半結構化數據。架構

至於數據存儲,要考慮的是選什麼樣的數據庫以及怎麼設計 schema。選關係數據庫仍是NoSQL 數據庫?要不要用內存數據庫?要不要用圖數據庫?這些都須要根據數據場景慎重選擇。框架

CN-DBpedia 其實是基於 mongo 數據庫,參與開發的謝晨昊提到,通常只有在基於特定領域纔可能會用到圖數據庫,就知識圖譜而言,基於 json (bson) 的 mongo 就足夠了。用到圖查詢的領域如徵信,通常是須要要找兩個公司之間的關聯交易,會用到最短路徑/社區計算等。scrapy

schema 的重要性不用多說,高質量、標準化的 schema 能有效下降領域數據之間對接的成本。咱們但願達到的效果是,對於任何數據,進入知識圖譜後後續流程都是相同的。換言之,對於不一樣格式、不一樣來源、不一樣內容的數據,在接入知識圖譜時都會按照預約義的 schema 對數據進行轉換和清洗,無縫使用已有元數據和資源。

3. 知識融合層

咱們知道,目前分佈在互聯網上的知識經常以分散、異構、自治的形式存在,另外還具備冗餘、噪音、不肯定、非完備的特色,清洗並不能解決這些問題,所以從這些知識出發,一般須要融合和驗證的步驟,來將不一樣源不一樣結構的數據融合成統一的知識圖譜,以保證知識的一致性。

因此數據支持層往上一層其實是融合層,主要工做是對獲取的數據進行標註、抽取,獲得大量的三元組,並對這些三元組進行融合,去冗餘、去衝突、規範化。

第一部分 SPO 三元組抽取,對不一樣種類的數據用不一樣的技術提取:

  • 從結構化數據庫中獲取知識:D2R

難點:複雜表數據的處理

  • 從連接數據中獲取知識:圖映射

難點:數據對齊

  • 從半結構化(網站)數據中獲取知識:使用包裝器

難點:方便的包裝器定義方法,包裝器自動生成、更新與維護

  • 從文本中獲取知識:信息抽取

難點:結果的準確率與覆蓋率

尤爲是純文本數據會涉及到的實體識別、實體連接、實體關係識別、概念抽取 等,須要用到許多天然語言處理的技術,包括但不只限於分詞、詞性標註、分佈式語義表達、篇章潛在主題分析、同義詞構建、語義解析、依存句法、語義角色標註、語義類似度計算等等。

第二部分纔到融合,目的是將不一樣數據源獲取的知識進行融合構建數據之間的關聯。包括實體對齊、屬性對齊、衝突消解、規範化等,這一部分不少都是 dirty work,更多的是作一個數據的映射、實體的匹配,可能還會涉及的是本體的構建和融合。最後融合而成的知識庫存入上一部分提到的數據庫中。若有必要,也須要如 Spark 等大數據平臺提供高性能計算能力,支持快速運算。

知識融合的四個難點:

  • 實現不一樣來源、不一樣形態數據的融合
  • 海量數據的高效融合
  • 新增知識的實時融合
  • 多語言的融合

4. 知識驗證

再往上一層主要是驗證,分爲補全、糾錯、外鏈、更新各部分,確保知識圖譜的一致性和準確性。

一個典型問題是,知識圖譜的構建不是一個靜態的過程,當引入新知識時,須要判斷新知識是否正確,與已有知識是否一致,若是新知識與舊知識間有衝突,那麼要判斷是原有的知識錯了,仍是新的知識不靠譜?這裏能夠用到的證據能夠是權威度、冗餘度、多樣性、一致性等。若是新知識是正確的,那麼要進行相關實體和關係的更新。

5. 知識計算和應用

這一部分主要是基於知識圖譜計算功能以及知識圖譜的應用。知識計算主要是根據圖譜提供的信息獲得更多隱含的知識,像是經過本體或者規則推理技術能夠獲取數據中存在的隱含知識;經過連接預測預測實體間隱含的關係;經過社區計算在知識網絡上計算獲取知識圖譜上存在的社區,提供知識間關聯的路徑……經過知識計算知識圖譜能夠產生大量的智能應用如專家系統、推薦系統、語義搜索、問答等。

知識圖譜涉及到的技術很是多,每一項技術都須要專門去研究,並且已經有不少的研究成果。Anyway 這章不是來論述知識圖譜的具體技術,而是講怎麼作一個 hello world 式的行業知識圖譜。

這裏講兩個小 demo,一個是爬蟲+mysql+d3 的小型知識圖譜,另外一個是基於 CN-DBpedia+爬蟲+PostgreSQL+d3 的」增量型」知識圖譜,要實現的是某行業上市公司與其高管之間的關係圖譜。

6. 數據獲取

第一個重要問題是,咱們須要什麼樣的知識?須要爬什麼樣的數據?

通常在數據獲取以前會先作個知識建模,創建知識圖譜的數據模式,能夠採用兩種方法:一種是自頂向下的方法,專家手工編輯造成數據模式;另外一種是自底向上的方法,基於行業現有的標準進行轉換或者從現有的高質量行業數據源中進行映射。數據建模都過程很重要,由於標準化的 schema 能有效下降領域數據之間對接的成本。

做爲一個簡單的 demo,咱們只作上市公司和高管之間的關係圖譜,企業信息就用公司註冊的基本信息,高管信息就用基本的姓名、出生年、性別、學歷這些。

而後開始寫爬蟲,爬蟲看着簡單,實際有不少的技巧,怎麼作優先級調度,怎麼並行,怎麼屏蔽規避,怎麼在遵照互聯網協議的基礎上最大化爬取的效率,有不少小的 trick,以前博客裏也說了不少,就不展開了,要注意的一點是,高質量的數據來源是成功的一半!

來扯一扯爬取建議:

  • 從數據質量來看,優先考慮權威的、穩定的、數據格式規整且先後一致、數據完整的網頁
  • 從爬取成原本看,優先考慮免登陸、免驗證碼、無訪問限制的頁面
  • 爬下來的數據務必保存好爬取時間、爬取來源(source)或網頁地址(url)

source 能夠是新浪財經這類的簡單標識,url 則是網頁地址,這些在後續數據清洗以及以後的糾錯(權威度計算)、外鏈和更新中很是重要

企業信息能夠在天眼查、啓信寶、企查查各類網站查到,信息還蠻全的,不過有訪問限制,須要註冊登陸,還有驗證碼的環節,固然能夠過五關斬六將爬到咱們要的數據,然而沒這個必要,換別個網站就好。

推薦兩個數據來源: 中財網數據引擎和巨潮資訊,其中巨潮資訊還能夠同時爬取高管以及公告信息。

看一下數據:

 

換句話說,咱們直接能獲得規範的實體(公司、人),以及規範的關係(高管),固然也能夠把高管展開,用下一層關係,董事長、監事之類,這就須要作進一步的清洗,也可能須要作關係的對齊。

這裏爬蟲框架我用的是 scrapy+redis 分佈式,天天能夠定時爬取,爬下來的數據寫好自動化清洗腳本,定時入庫。

7. 數據存儲

數據存儲是很是重要的一環,第一個問題是選什麼數據庫,這裏做爲 starter,用的是關係型數據庫 MySQL。設計了四張表,兩張實體表分別存公司(company)和人物(person)的信息,一張關係表存公司和高管的對應關係(management),最後一張 SPO 表存三元組。

爲何爬下來兩張表,存儲卻要用 4 張表?

一個考慮是知識圖譜裏典型的一詞多義問題,相同實體名但有可能指向不一樣的意義,好比說 Paris 既能夠表示巴黎,也能夠表示人名,怎麼辦?讓做爲地名的 「Paris」 和做爲人的 「Paris」 有各自獨一無二的ID。「Paris1」(巴黎)經過一種內在關係與埃菲爾鐵塔相聯,而 「Paris2」(人)經過取消關係與各類真人秀相聯。

這裏也是同樣的場景,同名同姓不一樣人,須要用 id 作惟一性標識,也就是說咱們須要對原來的數據格式作一個轉換,不一樣的張三要標識成張三1,張三2… 那麼,用什麼來區別人呢?

拍腦殼想用姓名、生日、性別來定義一我的,也就是說咱們須要一張人物表,須要(name, birth, sex)來做 composite unique key 表示每一個人。公司也是相同的道理,不過這裏只有上市公司,股票代碼就能夠做爲惟一性標識。

Person 表和 company 表是多對多的關係,這裏須要作 normalization,用 management 這張表來把多對多轉化爲兩個一對多的關係,(person_id, company_id)就表示了這種映射。

management 和 spo 表都表示了這種映射,爲何用兩張表呢?是出於實體對齊的考慮。management 保存了原始的關係,」董事」、監事」等,而 spo 把這些關係都映射成」高管」,也就是說 management 可能須要經過映射才能獲得 SPO 表,SPO 纔是最終成型的表。

咱們知道知識庫裏的關係其實有兩種,一種是屬性(property),一種是關係(relation)。那麼還有一個問題是 SPO 需不須要存儲屬性?

最初的想法是實體歸實體,屬性歸屬性,SPO 只存實體間的關係,屬性由實體表檢索獲得,然而這樣的話須要多表 JOIN,屬性增長時擴展性也不好。所以把屬性也存到 SPO 表中。在 SPO 表中多加一列 type,來區分這關係是實體間關係仍是實體與屬性的關係,便於以後的可視化。

最後要注意的一點是,每條記錄要保存建立時間以及最後更新時間,作一個簡單的版本控制。

8. 數據可視化

Flask 作 server,d3 作可視化,能夠檢索公司名/人名獲取相應的圖譜,以下圖。以後會試着更新有向圖版本。

 

 

9. Start from CN-DBpedia

把 CN-DBpedia 的三元組數據,大概 6500 萬條,導入數據庫,這裏嘗試了 PostgreSQL。而後檢索了 112 家上市公司的註冊公司名稱,只有 69 家公司返回告終果,屬性、關係都不是很完善,說明了通用知識圖譜有其不完整性。

也有可能須要先作一次 mention2entity,可能它的標準實體並非註冊信息的公司名稱,不過 API 小範圍試了下不少是 Unknown Mention。

作法也很簡單,把前面 Start from scratch 中獲得的 SPO 表插入到這裏的 SPO 表就行了。這麼簡單?由於這個場景下不用作實體對齊和關係對齊。

10. 拓展

這只是個 hello world 項目,在此基礎上能夠進行不少有趣的拓展,最相近的好比說加入企業和股東的關係,能夠進行企業最終控制人查詢(e.g.,基於股權投資關係尋找持股比例最大的股東,最終追溯至天然人或國有資產管理部門)。再日後能夠作企業社交圖譜查詢、企業與企業的路徑發現、企業風險評估、反欺詐等等等等。

具體來講:

  1. 從新設計數據模型 引入」概念」,造成可動態變化的「概念—實體—屬性—關係」數據模型,實現各種數據的統一建模;
  2. 擴展多源、異構數據,結合實體抽取、關係抽取等技術,填充數據模型;
  3. 展開知識融合(實體連接、關係連接、衝突消解等)、驗證工做(糾錯、更新等)。

最後補充一下用 Neo4j 方式產生的可視化圖,有兩種方法。

一是把上面說到的 MySQL/PostgreSQL 裏的 company 表和 person 表存成 node,node 之間的關係由 spo 表中 type == relation 的 record 中產生;

二是更直接的,從 spo 表中,遇到 type == property 就給 node(subject) 增長屬性 ({predicate:object}),遇到 type == relation 就給 node 增長關係 ((Nsubject) - [r:predicate]-> node(Nobject)),獲得下面的圖,移動鼠標到相應位置就能夠在下方查看到關係和節點的屬性。

相關文章
相關標籤/搜索