你會怎么選擇數據庫,是關系數據庫、XML 數據庫、資源描述框架(RDF),還是圖形數據庫? 本文的第1部分 深入而生動地探討了各種選擇。在第2部分,將深入介紹使用 Neo4j 的注意點。文章系國內 ITOM 管理平臺 OneAPM 編譯呈現。
過渡到 Neo4j 之后的經驗和教訓
下面介紹一些有關運行 Neo4j 的實用技巧:
1. 如果你是 Java 商城,請嵌入式地運行 Neo4j
Neo4j 是本地 Java 平臺,我們又是 Java 商城,用 Neo4j 相當合適。嵌入 Neo4j 讓我們不用再進行 REST 調用,這對于安全來說確實很重要。有關進行 REST 調用的進一步危害,請觀看這段有關 REST 安全漏洞的 JavaOne 討論。
嵌入式地運行 Neo4j 還為我們大幅降低了復雜性。我們可以直接在進程中調用 Neo4j API,從而快速了解Cypher 語言,以便運行 Cypher 和 Java API 這兩者的結合體。同時我們再也不需要托管和非托管的擴展了。
2. 摸清自己的優勢
摸清自己的優勢和所選擇的工具的優勢,這一點極為重要。用工具來做不適當的事,效果會大打折扣。
本地圖形數據庫在關系方面的表現確實很好;在圖形中找到切入點,然后按照需要深入地研究各種關系,這在 Neo4j 中快得驚人。但如果想要在單個節點之外進行復雜的多值屬性全文檢索,效果就大打折扣了 —— 但我們選擇圖形數據庫并不是為了做這個。
3. 了解查詢時會發生哪些事情
了解查詢時會發生哪些事情,這一點也極為重要,這能夠優化 Cypher 語言。
請看下面這個非常簡單的查詢。我想要找到 Franklin Country 所有擁有狩獵執照的男性,并且執照上的地址需要和此人的家庭住址相匹配,以便我們確認這是同一個人。
我有一個人員節點,一個執照節點,還有一個位置節點,每個節點上都有各種不同屬性:
數據庫要做的第一件事就是找到切入點(可能有多個切入點),然后圖形從切入點展開搜索。尋找切入點通常是個讓人頭痛的問題。為此要使用帶有靜態索引集的基于規則的規劃程序,這一軟件已于近期升級為基于費用。這雖然還不夠完美,但無疑已經朝著正確的方向前進了一大步。
索引
索引基本上會復制數據庫中的信息片段,這樣有利于它迅速找到節點。在本例中,只使用信息片段來確定切入點。雖然不是必須要使用索引,但它確實能派上用場。如果要在特定的節點屬性上進行檢索,在節點上設置一個索引會是個好辦法,即使這會占用磁盤空間。
索引分為兩種:schema 和 legacy。Schema 索引是最新版,使用內部自定義的 Neo4j 內置索引,目前是默認設置。
一旦利用 Cypher 或 Java API 創建 schema 索引后,這些索引就會自動由數據庫維護。例如,如果你想在每個帶有“人員”標簽和“性別”屬性的節點上創建索引,當你創建新節點、更改節點值或刪除節點時,數據庫將自動對其進行更新。這時你也可以設置限定條件,比如必須存在屬性或屬性必須是唯一的。
Legacy 索引是 Lucene 索引,是較早的版本但尚未棄用。可以通過配置文件、Neo4j 屬性文件、Java API 或 Cypher 來設置 legacy 索引。Legacy 索引使用的是 Lucene 而非 Neo4j 專有索引機制。我們在用 Neo4j 時幾乎沒有什么漏洞,而每次遇到的漏洞基本都和 legacy 索引有關。即使是這樣,有時候這些索引也是必要的。
Apache Luke 是一款非常不錯的開源工具,用戶可以用它直接查看和搜索 Lucene 索引。這也幫助我們修復了 legacy 索引中的異常行為。
自動索引與手動索引
Legacy 索引有兩種用法:自動索引和手動索引。我建議使用自動索引,因為它更容易維護。基本上只要設置一次(可以在配置文件中設置也可以通過 API 設置),然后設為在特定類型的節點上為特定類型的屬性編寫索引。自動索引還能夠在必要時輕松重建索引。
但是用戶無法指定是哪種類型的索引。在 Lucene 中,schema 存在不同索引類型,例如字符串、區分大小寫,以及數值,這些都是物理上獨立的索引。
如果你在查詢 Lucene 時想要使用這些索引,必須要做的第一件事就是告訴 Lucene 要使用哪個索引。但如果進行自動索引,Neo4j 可以根據你要編寫索引的第一個對象來選擇使用哪個索引。例如,如果你設置的第一個索引是藍色,Neo4j 就會明白藍色是字符串,然后會永久性地將藍色放在字符串索引中。
如果你能很好地控制收到的數據,這一索引方式效果會很不錯。但我們的系統沒有這樣。我們從許多不同的來源接收數據,所以收到的“blue”(藍色)屬性可能會指年齡。但如果這一屬性是最先收到的,Neo4j 就會把年齡作為基于字符串的屬性而不是數值屬性來編寫索引,如此一來,之后就沒法按照我希望的方式展開進一步比對和排列了。在這種情況下,只能手動創建索引。
使用自動索引的另一個好處是,如果目錄無故損壞,很容易就能修復目錄。可以暫停整個數據庫,進入 Lucene 索引目錄,刪除此目錄,重啟數據庫,然后 Neo4j 會為所有節點重新編寫索引。但如果已經進行了手動索引,你只能返回,然后為所有節點重新編寫索引。
范圍查詢
下面一系列幻燈片顯示了范圍查詢:
我想查詢“profile”(個人信息),所以我把 PROFILE 放在查詢內容的前面。我想找到收入為特定數值(50500)的所有人群并且只返回最前面的兩個結果。
這段代碼表明,我已經有了某人的收入索引,規劃程序的限值是 2。 NodeIndexSeek 用這一索引來查找數值,從一個擁有 22 萬人的樣本數據庫中進行了大約 2800 次數據庫訪問。
在接下來的范圍查詢中,我準備查找收入低于 50500 的人:
在這次的查詢中,我們執行了 NodeByLabelScan ,由于沒有使用索引,我們進行了多達 43 萬次數據庫訪問。在 Neo4j 第 2.3 版之前,schema 索引不支持范圍,所以你必須得用 legacy 索引,然后直接查詢 Lucene 索引,才能發揮作用。
第 2.3 版修復了這一問題;現在有了 NodeIndexSeekByRange ,可在 schema 標簽上提供范圍索引:
4. 不要使用內部節點 ID
使用當前節點 ID 是個很大的誘惑,但這種做法非常不可取,這是因為在某些時刻,這種做法會導致數據庫內容被刪除。請閱讀這篇介紹,了解更多相關內容。
Neo4j 使用增量日志。如果你刪除了某個節點,最后系統會翻轉節點 ID,這樣你就可以重復使用這些數字。我們結合使用了節點標簽和隨機選擇的 UUID,這樣如果你的 API 始終暴露在外,就可以提供額外的安全保障。
5. 數據建模很重要
數據模型的重要程度至少和查詢相當。下面的說明很有用:可以通過多重關系類型或關系上的屬性來為部分關系建模。兩種方法似乎同樣合理,但它們的性能表現可能大相徑庭。一定要了解一下 GraphAware 對這一內容的介紹。其區別在于,一方定義不同類型的 person 和 place 之間的關系……
……而另一方則表示有三種不同的屬性類型:
性能表現提升了八倍。上述 GraphAware 的文章深入詳細地解釋了這一概念。
6. 優化性能
EXPLAIN 和 PROFILE 絕對是你的良師益友。別擔心 Java API,而查詢規劃程序還很年輕,在許多情況下都比 Cypher 要快。如果你要設定基準,一定要以溫備份數據庫設定基準。這樣就能加載 Neo4j 的數據庫緩存。
7. 一定要交流!
Neo4j 擁有強大的支持社區,包括谷歌論壇、Slack 協作頻道、Stack Overflow 網站和非常出色的支持團隊。
8. 在工具欄里添加下面的代碼
借助下面的樣板代碼,可以檢查數據庫中的每個節點并修復所有問題。這一示例有時會抓取關系,但你也可以對節點或其他限定條件進行同樣的操作。
不管怎樣,它都能事務性地依次通過數據庫中的所有節點。在本例中,每個事務是 90000 次操作,如果有需要,還可以批量更改整個數據庫:
英文原文:https://dzone.com/articles/from-good-to-graph-choosing-the-right-database
由國內 ITOM 管理平臺 OneAPM 編譯呈現
鏈接:http://blog.oneapm.com/apm-tech/740.html