【編者按】你會(huì)怎么選擇數(shù)據(jù)庫,是關(guān)系數(shù)據(jù)庫褒搔、XML 數(shù)據(jù)庫阶牍、資源描述框架(RDF),還是圖形數(shù)據(jù)庫星瘾?本文的第1部分深入而生動(dòng)地探討了各種選擇走孽。在第2部分,將深入介紹使用 Neo4j 的注意點(diǎn)琳状。文章系國內(nèi) ITOM 管理平臺 OneAPM 編譯呈現(xiàn)磕瓷。
過渡到 Neo4j 之后的經(jīng)驗(yàn)和教訓(xùn)
下面介紹一些有關(guān)運(yùn)行 Neo4j 的實(shí)用技巧:
1. 如果你是 Java 商城,請嵌入式地運(yùn)行 Neo4j
Neo4j 是本地 Java 平臺念逞,我們又是 Java 商城困食,用 Neo4j 相當(dāng)合適。嵌入 Neo4j 讓我們不用再進(jìn)行 REST 調(diào)用翎承,這對于安全來說確實(shí)很重要陷舅。有關(guān)進(jìn)行 REST 調(diào)用的進(jìn)一步危害,請觀看這段有關(guān) REST 安全漏洞的 JavaOne 討論审洞。
嵌入式地運(yùn)行 Neo4j 還為我們大幅降低了復(fù)雜性。我們可以直接在進(jìn)程中調(diào)用 Neo4j API待讳,從而快速了解 Cypher 語言芒澜,以便運(yùn)行 Cypher 和 Java API 這兩者的結(jié)合體。同時(shí)我們再也不需要托管和非托管的擴(kuò)展了创淡。
2. 摸清自己的優(yōu)勢
摸清自己的優(yōu)勢和所選擇的工具的優(yōu)勢痴晦,這一點(diǎn)極為重要。用工具來做不適當(dāng)?shù)氖铝詹剩Ч麜?huì)大打折扣誊酌。
本地圖形數(shù)據(jù)庫在關(guān)系方面的表現(xiàn)確實(shí)很好;在圖形中找到切入點(diǎn)露乏,然后按照需要深入地研究各種關(guān)系碧浊,這在 Neo4j 中快得驚人。但如果想要在單個(gè)節(jié)點(diǎn)之外進(jìn)行復(fù)雜的多值屬性全文檢索瘟仿,效果就大打折扣了 —— 但我們選擇圖形數(shù)據(jù)庫并不是為了做這個(gè)箱锐。
3. 了解查詢時(shí)會(huì)發(fā)生哪些事情
了解查詢時(shí)會(huì)發(fā)生哪些事情,這一點(diǎn)也極為重要劳较,這能夠優(yōu)化 Cypher 語言驹止。
請看下面這個(gè)非常簡單的查詢浩聋。我想要找到 Franklin Country 所有擁有狩獵執(zhí)照的男性,并且執(zhí)照上的地址需要和此人的家庭住址相匹配臊恋,以便我們確認(rèn)這是同一個(gè)人衣洁。
我有一個(gè)人員節(jié)點(diǎn),一個(gè)執(zhí)照節(jié)點(diǎn)抖仅,還有一個(gè)位置節(jié)點(diǎn)坊夫,每個(gè)節(jié)點(diǎn)上都有各種不同屬性:
數(shù)據(jù)庫要做的第一件事就是找到切入點(diǎn)(可能有多個(gè)切入點(diǎn))践樱,然后圖形從切入點(diǎn)展開搜索。尋找切入點(diǎn)通常是個(gè)讓人頭痛的問題凸丸。為此要使用帶有靜態(tài)索引集的基于規(guī)則的規(guī)劃程序拷邢,這一軟件已于近期升級為基于費(fèi)用。這雖然還不夠完美屎慢,但無疑已經(jīng)朝著正確的方向前進(jìn)了一大步瞭稼。
索引
索引基本上會(huì)復(fù)制數(shù)據(jù)庫中的信息片段,這樣有利于它迅速找到節(jié)點(diǎn)腻惠。在本例中环肘,只使用信息片段來確定切入點(diǎn)。雖然不是必須要使用索引集灌,但它確實(shí)能派上用場悔雹。如果要在特定的節(jié)點(diǎn)屬性上進(jìn)行檢索,在節(jié)點(diǎn)上設(shè)置一個(gè)索引會(huì)是個(gè)好辦法欣喧,即使這會(huì)占用磁盤空間腌零。
索引分為兩種:schema 和 legacy。Schema 索引是最新版唆阿,使用內(nèi)部自定義的 Neo4j 內(nèi)置索引益涧,目前是默認(rèn)設(shè)置。
一旦利用 Cypher 或 Java API 創(chuàng)建 schema 索引后驯鳖,這些索引就會(huì)自動(dòng)由數(shù)據(jù)庫維護(hù)闲询。例如,如果你想在每個(gè)帶有“人員”標(biāo)簽和“性別”屬性的節(jié)點(diǎn)上創(chuàng)建索引浅辙,當(dāng)你創(chuàng)建新節(jié)點(diǎn)扭弧、更改節(jié)點(diǎn)值或刪除節(jié)點(diǎn)時(shí),數(shù)據(jù)庫將自動(dòng)對其進(jìn)行更新记舆。這時(shí)你也可以設(shè)置限定條件寄狼,比如必須存在屬性或?qū)傩员仨毷俏ㄒ坏摹?/p>
Legacy 索引是 Lucene 索引,是較早的版本但尚未棄用〔蠢ⅲ可以通過配置文件伊磺、Neo4j 屬性文件、Java API 或 Cypher 來設(shè)置 legacy 索引删咱。Legacy 索引使用的是 Lucene 而非 Neo4j 專有索引機(jī)制屑埋。我們在用 Neo4j 時(shí)幾乎沒有什么漏洞,而每次遇到的漏洞基本都和 legacy 索引有關(guān)痰滋。即使是這樣摘能,有時(shí)候這些索引也是必要的。
Apache Luke 是一款非常不錯(cuò)的開源工具敲街,用戶可以用它直接查看和搜索 Lucene 索引团搞。這也幫助我們修復(fù)了 legacy 索引中的異常行為。
自動(dòng)索引與手動(dòng)索引
Legacy 索引有兩種用法:自動(dòng)索引和手動(dòng)索引多艇。我建議使用自動(dòng)索引,因?yàn)樗菀拙S護(hù)峻黍「绰。基本上只要設(shè)置一次(可以在配置文件中設(shè)置也可以通過 API 設(shè)置)姆涩,然后設(shè)為在特定類型的節(jié)點(diǎn)上為特定類型的屬性編寫索引。自動(dòng)索引還能夠在必要時(shí)輕松重建索引骨饿。
但是用戶無法指定是哪種類型的索引亏栈。在 Lucene 中,schema 存在不同索引類型宏赘,例如字符串仑扑、區(qū)分大小寫,以及數(shù)值置鼻,這些都是物理上獨(dú)立的索引。
如果你在查詢 Lucene 時(shí)想要使用這些索引蜓竹,必須要做的第一件事就是告訴 Lucene 要使用哪個(gè)索引箕母。但如果進(jìn)行自動(dòng)索引,Neo4j 可以根據(jù)你要編寫索引的第一個(gè)對象來選擇使用哪個(gè)索引俱济。例如嘶是,如果你設(shè)置的第一個(gè)索引是藍(lán)色,Neo4j 就會(huì)明白藍(lán)色是字符串蛛碌,然后會(huì)永久性地將藍(lán)色放在字符串索引中聂喇。
如果你能很好地控制收到的數(shù)據(jù),這一索引方式效果會(huì)很不錯(cuò)。但我們的系統(tǒng)沒有這樣希太。我們從許多不同的來源接收數(shù)據(jù)克饶,所以收到的“blue”(藍(lán)色)屬性可能會(huì)指年齡。但如果這一屬性是最先收到的誊辉,Neo4j 就會(huì)把年齡作為基于字符串的屬性而不是數(shù)值屬性來編寫索引矾湃,如此一來,之后就沒法按照我希望的方式展開進(jìn)一步比對和排列了堕澄。在這種情況下邀跃,只能手動(dòng)創(chuàng)建索引。
使用自動(dòng)索引的另一個(gè)好處是蛙紫,如果目錄無故損壞拍屑,很容易就能修復(fù)目錄】痈担可以暫停整個(gè)數(shù)據(jù)庫僵驰,進(jìn)入 Lucene 索引目錄,刪除此目錄裁蚁,重啟數(shù)據(jù)庫矢渊,然后 Neo4j 會(huì)為所有節(jié)點(diǎn)重新編寫索引。但如果已經(jīng)進(jìn)行了手動(dòng)索引枉证,你只能返回矮男,然后為所有節(jié)點(diǎn)重新編寫索引。
范圍查詢
下面一系列幻燈片顯示了范圍查詢:
我想查詢“profile”(個(gè)人信息),所以我把 PROFILE
放在查詢內(nèi)容的前面秒赤。我想找到收入為特定數(shù)值(50500)的所有人群并且只返回最前面的兩個(gè)結(jié)果猪瞬。
這段代碼表明,我已經(jīng)有了某人的收入索引入篮,規(guī)劃程序的限值是 2陈瘦。NodeIndexSeek
用這一索引來查找數(shù)值,從一個(gè)擁有 22 萬人的樣本數(shù)據(jù)庫中進(jìn)行了大約 2800 次數(shù)據(jù)庫訪問潮售。
在接下來的范圍查詢中痊项,我準(zhǔn)備查找收入低于 50500 的人:
在這次的查詢中鞍泉,我們執(zhí)行了 NodeByLabelScan
,由于沒有使用索引肮帐,我們進(jìn)行了多達(dá) 43 萬次數(shù)據(jù)庫訪問咖驮。在 Neo4j 第 2.3 版之前,schema 索引不支持范圍,所以你必須得用 legacy 索引托修,然后直接查詢 Lucene 索引忘巧,才能發(fā)揮作用。
第 2.3 版修復(fù)了這一問題诀黍;現(xiàn)在有了 NodeIndexSeekByRange
袋坑,可在 schema 標(biāo)簽上提供范圍索引:
4. 不要使用內(nèi)部節(jié)點(diǎn) ID
使用當(dāng)前節(jié)點(diǎn) ID 是個(gè)很大的誘惑枣宫,但這種做法非常不可取,這是因?yàn)樵谀承r(shí)刻吃环,這種做法會(huì)導(dǎo)致數(shù)據(jù)庫內(nèi)容被刪除也颤。請閱讀這篇介紹,了解更多相關(guān)內(nèi)容郁轻。
Neo4j 使用增量日志翅娶。如果你刪除了某個(gè)節(jié)點(diǎn),最后系統(tǒng)會(huì)翻轉(zhuǎn)節(jié)點(diǎn) ID好唯,這樣你就可以重復(fù)使用這些數(shù)字竭沫。我們結(jié)合使用了節(jié)點(diǎn)標(biāo)簽和隨機(jī)選擇的 UUID,這樣如果你的 API 始終暴露在外骑篙,就可以提供額外的安全保障蜕提。
5. 數(shù)據(jù)建模很重要
數(shù)據(jù)模型的重要程度至少和查詢相當(dāng)。下面的說明很有用:可以通過多重關(guān)系類型或關(guān)系上的屬性來為部分關(guān)系建模靶端。兩種方法似乎同樣合理谎势,但它們的性能表現(xiàn)可能大相徑庭。一定要了解一下 GraphAware 對這一內(nèi)容的介紹杨名。其區(qū)別在于脏榆,一方定義不同類型的 person
和 place
之間的關(guān)系……
……而另一方則表示有三種不同的屬性類型:
性能表現(xiàn)提升了八倍趁蕊。上述 GraphAware 的文章深入詳細(xì)地解釋了這一概念坞生。
6. 優(yōu)化性能
EXPLAIN
和 PROFILE
絕對是你的良師益友。別擔(dān)心 Java API介衔,而查詢規(guī)劃程序還很年輕,在許多情況下都比 Cypher 要快骂因。如果你要設(shè)定基準(zhǔn)炎咖,一定要以溫備份數(shù)據(jù)庫設(shè)定基準(zhǔn)。這樣就能加載 Neo4j 的數(shù)據(jù)庫緩存。
7. 一定要交流乘盼!
Neo4j 擁有強(qiáng)大的支持社區(qū)升熊,包括谷歌論壇、Slack 協(xié)作頻道绸栅、Stack Overflow 網(wǎng)站和非常出色的支持團(tuán)隊(duì)级野。
8. 在工具欄里添加下面的代碼
借助下面的樣板代碼,可以檢查數(shù)據(jù)庫中的每個(gè)節(jié)點(diǎn)并修復(fù)所有問題粹胯。這一示例有時(shí)會(huì)抓取關(guān)系蓖柔,但你也可以對節(jié)點(diǎn)或其他限定條件進(jìn)行同樣的操作。
不管怎樣风纠,它都能事務(wù)性地依次通過數(shù)據(jù)庫中的所有節(jié)點(diǎn)况鸣。在本例中,每個(gè)事務(wù)是 90000 次操作竹观,如果有需要镐捧,還可以批量更改整個(gè)數(shù)據(jù)庫:
本文系 OneAPM 工程師整理呈現(xiàn)懂酱。OneAPM 能為您提供端到端的應(yīng)用性能解決方案,我們支持所有常見的框架及應(yīng)用服務(wù)器誊抛,助您快速發(fā)現(xiàn)系統(tǒng)瓶頸列牺,定位異常根本原因。分鐘級部署芍锚,即刻體驗(yàn)昔园,性能監(jiān)控從來沒有如此簡單。想閱讀更多技術(shù)文章并炮,請?jiān)L問 OneAPM 官方技術(shù)博客默刚。
本文轉(zhuǎn)自 OneAPM 官方博客
原文地址:https://dzone.com/articles/from-good-to-graph-choosing-the-right-database