達(dá)觀數(shù)據(jù):知識(shí)圖譜和 Neo4j 淺析
在當(dāng)前大數(shù)據(jù)行業(yè)中, 隨著算法的升級(jí), 特別是機(jī)器學(xué)習(xí)的加入,“找規(guī)律”式的算法所帶來的“紅利”正在逐漸地消失,進(jìn)而需要一種可以對(duì)數(shù)據(jù)進(jìn)行更深一層挖掘的方式,這種新的方式就是知識(shí)圖譜。下面我們來聊一下知識(shí)圖譜以及知識(shí)圖譜在達(dá)觀數(shù)據(jù)中的實(shí)踐。
一,什么是知識(shí)圖譜
知識(shí)圖譜(Knowledge Graph)是一種用點(diǎn)來代替實(shí)體,用邊代替實(shí)體之間關(guān)系的一種語義網(wǎng)絡(luò)。通俗來說,知識(shí)圖譜就是把所有不同種類的信息(Heterogeneous Information)連接在一起而得到的一個(gè)關(guān)系網(wǎng)絡(luò),它提供了站在關(guān)系的角度去分析問題的視角。站在這個(gè)角度我們可以從“找規(guī)律”的維度上升到“理解”的維度, 這也就是為什么有人說知識(shí)圖譜是 AI 的未來。
“達(dá)觀數(shù)據(jù)是一家人工智能公司”這句話在機(jī)器看來只不過是一連串的字符, 但是在我們?nèi)丝磥韰s可以分成主謂賓三部分,即主語“達(dá)觀數(shù)據(jù)”謂語“是”賓語“人工智能公司”。 那么有沒有一種數(shù)據(jù)的組織形式讓機(jī)器看到這句話時(shí)不再是一個(gè)字符串, 而是一個(gè)具有類似主謂賓可以“理解”的結(jié)構(gòu)呢?當(dāng)然,這就是知識(shí)圖譜要干的事情。
知識(shí)圖譜可以表示成一個(gè)實(shí)體關(guān)系網(wǎng)絡(luò)圖,實(shí)體就是一個(gè)包含信息的個(gè)體,畫出來叫節(jié)點(diǎn);關(guān)系是兩個(gè)實(shí)體之間的聯(lián)系,畫出來叫邊。借用上面的例子“達(dá)觀數(shù)據(jù)是一家人工智能公司”,“達(dá)觀數(shù)據(jù)”和“人工智能公司”就是兩個(gè)實(shí)體,“是”即這兩個(gè)實(shí)體之間的關(guān)系。所以這句話用知識(shí)圖譜可以表示圖1。
圖1
二,知識(shí)圖譜的應(yīng)用場(chǎng)景
知道了什么是知識(shí)圖譜,那么知識(shí)圖譜有什么用處呢?這里我舉兩個(gè)例子:知識(shí)圖譜在搜索引擎中的作用以及在銀行風(fēng)控系統(tǒng)中的應(yīng)用。
1, 知識(shí)圖譜在搜索引擎中的應(yīng)用
有時(shí)候我們?cè)谑褂盟阉饕鏁r(shí), 我們的搜索詞(Query)往往看起來更像是一個(gè)問題,比如“張三是從哪里畢業(yè)的”,這時(shí)我們需要搜索引擎直接給出我想要的結(jié)果,而不是一個(gè)網(wǎng)頁排名(page rank) 。比如我在 Google 中搜索“扎克伯格的妻子是誰”, 我需要是扎克伯格的妻子普莉希拉?陳的詳細(xì)信息而不是一些包含了她信息的網(wǎng)頁。我們先看下 Google 的結(jié)果:
圖2
那么Google是怎么做到的呢?其實(shí)早在2012年Google 就已經(jīng)在搜索中加入了知識(shí)圖譜,用戶可以通過Google 構(gòu)建的知識(shí)圖譜直接查詢到結(jié)果,這種方式極大地提升了用戶體驗(yàn)。而且對(duì)于 Google 來說處理起來也比較便捷,首先將“扎克伯格的妻子是誰” 這個(gè) Query通過自然語言處理技術(shù)(NLP)處理成“扎克伯格”實(shí)體和”has_wife" 的關(guān)系,從已經(jīng)構(gòu)建好的知識(shí)圖譜中查詢, 然后將查詢結(jié)果返回給用戶。
然而就是這樣的一個(gè)改動(dòng),從用戶使用的角度來看已經(jīng)從普通的搜索引擎變成了智能問答的系統(tǒng),用戶體驗(yàn)上升了一個(gè)層次。
2,知識(shí)圖譜在隱含關(guān)系挖掘中的應(yīng)用。
馬克斯·韋伯曾說“人是懸掛在自我編織的意義之網(wǎng)上的動(dòng)物”,這句話從側(cè)面說明人與人之間的關(guān)系是很復(fù)雜的,我們是否可以將復(fù)雜的人際關(guān)系進(jìn)行一次挖掘呢?
首先人際關(guān)系實(shí)際形如一張網(wǎng), 既然是網(wǎng)那么它一定具有一個(gè)特性,即網(wǎng)上兩個(gè)相鄰節(jié)點(diǎn)之間的路徑損壞,并不一定影響整張網(wǎng)。比如一張網(wǎng)(無向圖)中相鄰的 A 節(jié)點(diǎn)到 B 節(jié)點(diǎn)的路徑“壞了”, 有極大可能找到另一條從 A 到 B 的路徑,而不影響整張網(wǎng)。那么網(wǎng)的這個(gè)特性應(yīng)該怎樣應(yīng)用到數(shù)據(jù)挖掘上來呢?我們來看一個(gè)知識(shí)圖譜在銀行風(fēng)控系統(tǒng)中的一個(gè)例子。
圖3
我們可以根據(jù)借款人借款時(shí)填寫的關(guān)系構(gòu)建知識(shí)圖譜, 如圖借款人跟張三是朋友關(guān)系,跟李四是父子關(guān)系。當(dāng)我們?cè)噲D把借款人的信息添加到知識(shí)圖譜里的時(shí)候,“一致性驗(yàn)證”引擎會(huì)觸發(fā)。引擎首先會(huì)去讀取張三和李四的關(guān)系,從而去驗(yàn)證這個(gè)“三角關(guān)系”是否正確。很顯然,朋友的朋友不是父子關(guān)系,所以存在著明顯的風(fēng)險(xiǎn)。這里的隱含關(guān)系挖掘可以借用通用的關(guān)系挖掘引擎,也可以自己實(shí)現(xiàn)隱含關(guān)系的挖掘引擎。通用關(guān)聯(lián)關(guān)系的挖掘由于其通用性,通常難以保證對(duì)關(guān)系挖掘的正確性,通常是自己配置規(guī)則來確保關(guān)系挖掘的準(zhǔn)確性。對(duì)隱含關(guān)系的挖掘技術(shù)目前是知識(shí)圖譜研究的前沿方向, 如果有興趣,可以查閱相關(guān)論文。
知識(shí)圖譜在銀行風(fēng)控中的作用還有很多,比如對(duì)失聯(lián)借款人兩度,甚至多度的關(guān)系挖掘來找到借款人等。 由此可見在“關(guān)系”越復(fù)雜的情況下,知識(shí)圖譜越是能發(fā)揮它的作用。
知識(shí)圖譜還有很多其他應(yīng)用場(chǎng)景,這里就不一一列舉了,如果您感興趣的話,參見《知識(shí)圖譜的應(yīng)用》(http://mp.weixin.qq.com/s/aRKS1CHNdh51010sZzBLlA)
三,知識(shí)圖譜的構(gòu)建
既然知識(shí)圖譜這么有用, 那么怎樣才能構(gòu)建自己的知識(shí)圖譜,怎樣將傳統(tǒng)的數(shù)據(jù)轉(zhuǎn)化成知識(shí)圖譜呢?
傳統(tǒng)數(shù)據(jù)主要分成兩種,格式化數(shù)據(jù)和非格式化數(shù)據(jù)。格式化數(shù)據(jù)轉(zhuǎn)化成知識(shí)圖譜時(shí)需要將格式化的數(shù)據(jù)映射成實(shí)體關(guān)系組,從而構(gòu)建知識(shí)圖譜。而非格式化的數(shù)據(jù)轉(zhuǎn)化時(shí)比較復(fù)雜,通常采用算法抽取和程序抽取兩種方式。
1, 算法抽取方式:
通過自然語言處理(NLP)技術(shù)對(duì)文本進(jìn)行命名實(shí)體識(shí)別(NER),從非格式化的文本中識(shí)別出專有名詞和有意義的短語并進(jìn)行分類。比如上例中從“達(dá)觀數(shù)據(jù)是一家人工智能公司”這段文本中識(shí)別出”達(dá)觀數(shù)據(jù)”和“人工智能公司”這兩個(gè)實(shí)體以及“是”這個(gè)從屬關(guān)系,這樣我們就可以通過”達(dá)觀數(shù)據(jù)” “是” “人工智能公司” 這個(gè)實(shí)體組來構(gòu)建知識(shí)圖譜。由于目前NER識(shí)別技術(shù)還不夠成熟,通常我們會(huì)對(duì) NER 識(shí)別的實(shí)體進(jìn)行人工矯正,確保所識(shí)別實(shí)體的準(zhǔn)確性。
2, 程序抽取方式:
在處理實(shí)體識(shí)別非格式化數(shù)據(jù)的過程中,我們經(jīng)常會(huì)碰到半格式化的數(shù)據(jù),比如一段簡(jiǎn)歷的文本,文本中經(jīng)常會(huì)包含,姓名:XXX,公司名:XXX 等格式,遇到這樣的半格式化文本,我們也可以采用正則等方式來抽取,確保知識(shí)圖譜構(gòu)建的完整性和準(zhǔn)確性。
四, 知識(shí)圖譜的存儲(chǔ)以及 neo4j 的性能測(cè)試
知識(shí)圖譜是基于圖的數(shù)據(jù)結(jié)構(gòu),通常用圖數(shù)據(jù)庫(kù)進(jìn)行存儲(chǔ),我們先來看一下圖數(shù)據(jù)庫(kù)排行(部分)。數(shù)據(jù)來源DB-Engines Ranking(https://db-engines.com/en/ranking/graph+dbms)。
圖4
通過排行榜可以看出 Neo4j 數(shù)據(jù)庫(kù)***,實(shí)際上neo4j 已經(jīng)是當(dāng)前業(yè)界分析知識(shí)圖譜的主流數(shù)據(jù)庫(kù)。那么怎樣將 neo4j 圖數(shù)據(jù)庫(kù)應(yīng)用到項(xiàng)目中去,以及怎樣優(yōu)化 neo4j 圖數(shù)據(jù)庫(kù)呢?首先我們來看一下 neo4j 的性能表現(xiàn):
測(cè)試環(huán)境:
1, 操作系統(tǒng): Mac OS X 10.10.5
2, 內(nèi)存: 8G
3, CPU參數(shù): 8核8線程
4, 編程語言: python 2.7
5, Neo4j 版本: 3.3.0
6, 服務(wù)器節(jié)點(diǎn)數(shù): 單點(diǎn)
測(cè)試內(nèi)容: 節(jié)點(diǎn)數(shù)分別在1萬, 10萬, 100萬,1000萬情況下,在節(jié)點(diǎn)設(shè)置索引和不設(shè)置索引的情況下查找節(jié)點(diǎn)的平均延時(shí)。測(cè)試結(jié)果如下:
圖5
通過上面的測(cè)試可以看出,當(dāng)節(jié)點(diǎn)(Node)的數(shù)量超過1000萬時(shí),在不設(shè)置索引的情況下,平均查詢延時(shí)已經(jīng)超過了6秒,說明此時(shí) neo4j 已經(jīng)明顯“吃不消”了,顯然這樣的延時(shí)在實(shí)際的項(xiàng)目應(yīng)用中是完全不可接受的。但是我們發(fā)現(xiàn)設(shè)置索引之后查詢時(shí)間明顯降下來了,那么是不是設(shè)置的索引越多越好呢?我們看下在1000萬節(jié)點(diǎn)的情況下有索引和無索引插入延時(shí)測(cè)試:
圖6
由上圖測(cè)試結(jié)果可以看出: 在***數(shù)據(jù)的情況下有索引插入比無索引插入要慢30%, 所以索引并不是越多越好, 那么除此之外 neo4j 還有哪些地方可以優(yōu)化呢?
四,neo4j圖數(shù)據(jù)庫(kù)優(yōu)化
neo4j 不使用schema,所以從理論上來說 neo4j 可以存儲(chǔ)任何形式的數(shù)據(jù)。但由于neo4j 是通過鍵值對(duì)(Key-Value) 的雙向列表來保存節(jié)點(diǎn)和關(guān)系的屬性值,所以neo4j僅適用于存儲(chǔ)實(shí)體關(guān)系和實(shí)體簡(jiǎn)單的屬性。在實(shí)際應(yīng)用中一個(gè)實(shí)體通常會(huì)包含眾多的屬性,如果將這些屬性全部存儲(chǔ)到 neo4j 中,neo4j 的查詢將變得異常的慢, 而在實(shí)際的應(yīng)用場(chǎng)景下,經(jīng)常會(huì)遇到高并發(fā)的情況。這時(shí)候單節(jié)點(diǎn)的 neo4j 就會(huì)顯得力不從心。那么在項(xiàng)目實(shí)戰(zhàn)中怎樣更好的利用 neo4j 來抵御高并發(fā)呢?
1,高可用架構(gòu) :
neo4j HA(High Availability)即neo4j 的高可用特性,不過這個(gè)特征只能在neo4j 企業(yè)版中可用。neo4j HA使用多臺(tái)neo4j從數(shù)據(jù)庫(kù)設(shè)置替代單臺(tái)neo4j主數(shù)據(jù)庫(kù)的容錯(cuò)架構(gòu), 這種架構(gòu)可以在一臺(tái)實(shí)體機(jī)故障的情況下使數(shù)據(jù)庫(kù)具備完善讀寫操作的能力, 由于 neo4j HA 采用主從數(shù)據(jù)同步, 而且寫操作也可以在從庫(kù)中執(zhí)行(經(jīng)測(cè)試這種方式不如主節(jié)點(diǎn)寫入可靠),因此采用neo4j HA 比單臺(tái)neo4j數(shù)據(jù)庫(kù)擁有更多的讀取負(fù)載處理能力。
如果你使用的不是 neo4j 企業(yè)版,那么你可能需要自己動(dòng)手來構(gòu)建 neo4j 集群以此來實(shí)現(xiàn)高可用架構(gòu)了。當(dāng)然你可以采用Neo4j+DRBD(Distributed Replicated Block Device)+ Keepalived 方式來構(gòu)建自己的neo4j 集群, 通過 DRBD 來備份單點(diǎn)上的 neo4j 圖庫(kù)數(shù)據(jù),通過Keepalived 來管理你的集群。除此之外你還可以通過 zookeeper 來管理你的集群節(jié)點(diǎn),自己實(shí)現(xiàn)將主節(jié)點(diǎn)數(shù)據(jù)修改的Cypher 語句元操作同步到從節(jié)點(diǎn)(類似 MySQL 的binlog)來實(shí)現(xiàn)主從同步,從而達(dá)到讀寫分離。當(dāng)然不管你采用方式一還是方式二,都會(huì)增大開發(fā)和維護(hù)成本。
2, 增加緩存:
應(yīng)用緩存:在實(shí)際應(yīng)用的過程中讀寫圖庫(kù)時(shí)經(jīng)常會(huì)遇到查詢一些不常修改的數(shù)據(jù), 比如需要頻繁查詢用戶所屬的國(guó)家信息,而國(guó)家的屬性更改的頻率比較低,而且用戶的國(guó)籍信息不會(huì)經(jīng)常變動(dòng),這時(shí)我們可以通過添加應(yīng)用緩存(如:redis, leveldb等),將查詢的結(jié)果緩存起來,減少直接訪問圖庫(kù)的頻次,減小圖庫(kù)的讀取壓力。
數(shù)據(jù)庫(kù)緩存:由于neo4j 執(zhí)行一次查詢操作之后,會(huì)將數(shù)據(jù)緩存到內(nèi)存中,執(zhí)行相同的查詢操作 neo4j 直接返回內(nèi)存中緩存的數(shù)據(jù)結(jié)果。如果是執(zhí)行隨機(jī)查詢,則后一次結(jié)果會(huì)覆蓋前一次的查詢數(shù)據(jù),內(nèi)存緩存的配置可以通過修改配置文件中dbms.query_cache_size參數(shù)進(jìn)行調(diào)整。所以說執(zhí)行語句時(shí)盡可能的利用已有數(shù)據(jù)的緩存,減少 Cache-Miss 情況的發(fā)生。
3, 索引查詢優(yōu)化:
查詢優(yōu)化:由于 neo4j 會(huì)將查詢結(jié)果緩存到內(nèi)存中,所以不需要的查詢結(jié)果盡量不要放到內(nèi)存,比如 下面的cypher 語句:
1, MATCH (n) OPTIONAL MATCH (n)-[r]->() RETURN count(n.prop) + count(r.prop);
2, MATCH (n) OPTIONAL MATCH (n)-[r]->() RETURN count(*) + count(*);
語句1比語句2 更好,因?yàn)楹笳邥?huì)將所有的節(jié)點(diǎn)和關(guān)系的屬性加載到內(nèi)存,然后計(jì)算 count 值,而前者只會(huì)將必要的屬性加載到內(nèi)存求count值。
索引優(yōu)化:我們知道數(shù)據(jù)庫(kù)索引實(shí)際上是在數(shù)據(jù)之外維護(hù)了特定算法的數(shù)據(jù)結(jié)構(gòu)(如 B+Tree),比如圖7為了加快 Col2的查詢構(gòu)建一個(gè)二叉樹,使原來的“順序”查找,變成“二分查找”,從而將查詢復(fù)雜度降低為 o(logn),而且索引還會(huì)利用訪問局部性原理,充分利用操作系統(tǒng)的頁緩存,加快查找的速度。
圖7: 數(shù)據(jù)庫(kù)索引原理介紹
由于增加索引會(huì)讓圖庫(kù)維護(hù)在維護(hù)數(shù)據(jù)的同時(shí)還會(huì)維護(hù)一份額外的數(shù)據(jù)結(jié)構(gòu),更新數(shù)據(jù)時(shí)會(huì)造成額外的開銷,這也印證了上面測(cè)試的插入數(shù)據(jù)時(shí)無索引比有索引快的結(jié)論。
Neo4j 1.4以后的版本引入了自動(dòng)索引(automatic index),可以在config/neo4j.properties中配置自動(dòng)創(chuàng)建索引,也可以通過語句CREATE INDEX ON :Label(PropertyName)手動(dòng)創(chuàng)建索引,從而提高查詢的效率。 多屬性值也可設(shè)置聯(lián)合索引參見(https://neo4j.com/docs/developer-manual/current/cypher/schema/index/)。
4, Neo4j和KV(Key-Value)數(shù)據(jù)庫(kù)聯(lián)合使用
由于 neo4j 的節(jié)點(diǎn)和關(guān)系的屬性是通過Key-Value 的雙向列表來保存的,所以這種數(shù)據(jù)結(jié)決定了 neo4j 中存儲(chǔ)的節(jié)點(diǎn)不能包含太多的屬性值。但是在實(shí)際應(yīng)用中經(jīng)常會(huì)碰到一些實(shí)體擁有大量的屬性,必要時(shí)還需要通過這些屬性的值來查詢實(shí)體進(jìn)而查找實(shí)體擁有的關(guān)系。這時(shí)候可以將 neo4j 數(shù)據(jù)庫(kù)和KV 數(shù)據(jù)庫(kù)(如:MongoDB)進(jìn)行聯(lián)合使用,比如在 neo4j 節(jié)點(diǎn)的屬性中存儲(chǔ)MongoDB 中的 objectId。這樣既可以充分利用 neo4j 的特性來進(jìn)行關(guān)系查詢又可以通過 KV 數(shù)據(jù)庫(kù)的特性來進(jìn)行屬性到實(shí)體的查詢。通常在圖庫(kù)和 KV 數(shù)據(jù)庫(kù)聯(lián)合使用時(shí), 特別是經(jīng)常需要通過屬性來查詢實(shí)體時(shí)需要設(shè)置 neo4j schema Index,即將neo4j中與 KV 數(shù)據(jù)庫(kù)關(guān)聯(lián)的值設(shè)置索引。
總結(jié)與展望
知識(shí)圖譜和Neo4j還有很多有趣的特性,鑒于篇幅這里不再贅述。自Google在2012年推出知識(shí)圖譜技術(shù)以來,知識(shí)圖譜迎來了飛速的發(fā)展。由于知識(shí)圖譜在關(guān)系“理解”方面的優(yōu)勢(shì),目前已經(jīng)在各大互聯(lián)網(wǎng)公司和傳統(tǒng)企業(yè)的項(xiàng)目中落地,并取得了良好的效果。正是由于知識(shí)圖譜對(duì)數(shù)據(jù)理解和傳統(tǒng)方式不一致,給傳統(tǒng)的數(shù)據(jù)挖掘算法帶來了挑戰(zhàn)。相信隨著人們對(duì)知識(shí)圖譜的關(guān)注度越來越高,在知識(shí)圖譜領(lǐng)域?qū)?huì)涌現(xiàn)更多更成熟的構(gòu)建、存儲(chǔ)和挖掘理念,相信在不遠(yuǎn)的將來知識(shí)圖譜將會(huì)在更廣泛的領(lǐng)域內(nèi)為大家服務(wù)。
【本文為51CTO專欄作者“達(dá)觀數(shù)據(jù)”的原創(chuàng)稿件,轉(zhuǎn)載可通過51CTO專欄獲取聯(lián)系】