在選擇資料庫的路上,我們遇到過哪些坑?(2)

OneAPM官方技術部落格發表於2016-06-06

【編者按】你會怎麼選擇資料庫,是關聯式資料庫、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 所有擁有狩獵執照的男性,並且執照上的地址需要和此人的家庭住址相匹配,以便我們確認這是同一個人。

我有一個人員節點,一個執照節點,還有一個位置節點,每個節點上都有各種不同屬性:

在選擇資料庫的路上,我們遇到過哪些坑?(2)

資料庫要做的第一件事就是找到切入點(可能有多個切入點),然後圖形從切入點展開搜尋。尋找切入點通常是個讓人頭痛的問題。為此要使用帶有靜態索引集的基於規則的規劃程式,這一軟體已於近期升級為基於費用。這雖然還不夠完美,但無疑已經朝著正確的方向前進了一大步。

索引

索引基本上會複製資料庫中的資訊片段,這樣有利於它迅速找到節點。在本例中,只使用資訊片段來確定切入點。雖然不是必須要使用索引,但它確實能派上用場。如果要在特定的節點屬性上進行檢索,在節點上設定一個索引會是個好辦法,即使這會佔用磁碟空間。

索引分為兩種: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 會為所有節點重新編寫索引。但如果已經進行了手動索引,你只能返回,然後為所有節點重新編寫索引。

範圍查詢

下面一系列幻燈片顯示了範圍查詢:

在選擇資料庫的路上,我們遇到過哪些坑?(2)

我想查詢“profile”(個人資訊),所以我把 PROFILE 放在查詢內容的前面。我想找到收入為特定數值(50500)的所有人群並且只返回最前面的兩個結果。

這段程式碼表明,我已經有了某人的收入索引,規劃程式的限值是 2。NodeIndexSeek 用這一索引來查詢數值,從一個擁有 22 萬人的樣本資料庫中進行了大約 2800 次資料庫訪問。

在接下來的範圍查詢中,我準備查詢收入低於 50500 的人:

在選擇資料庫的路上,我們遇到過哪些坑?(2)

在這次的查詢中,我們執行了 NodeByLabelScan,由於沒有使用索引,我們進行了多達 43 萬次資料庫訪問。在 Neo4j 第 2.3 版之前,schema 索引不支援範圍,所以你必須得用 legacy 索引,然後直接查詢 Lucene 索引,才能發揮作用。

第 2.3 版修復了這一問題;現在有了 NodeIndexSeekByRange,可在 schema 標籤上提供範圍索引:

在選擇資料庫的路上,我們遇到過哪些坑?(2)

4. 不要使用內部節點 ID

使用當前節點 ID 是個很大的誘惑,但這種做法非常不可取,這是因為在某些時刻,這種做法會導致資料庫內容被刪除。請閱讀這篇介紹,瞭解更多相關內容。

Neo4j 使用增量日誌。如果你刪除了某個節點,最後系統會翻轉節點 ID,這樣你就可以重複使用這些數字。我們結合使用了節點標籤和隨機選擇的 UUID,這樣如果你的 API 始終暴露在外,就可以提供額外的安全保障。

5. 資料建模很重要

資料模型的重要程度至少和查詢相當。下面的說明很有用:可以通過多重關係型別或關係上的屬性來為部分關係建模。兩種方法似乎同樣合理,但它們的效能表現可能大相徑庭。一定要了解一下 GraphAware 對這一內容的介紹。其區別在於,一方定義不同型別的 personplace 之間的關係……

在選擇資料庫的路上,我們遇到過哪些坑?(2)

……而另一方則表示有三種不同的屬性型別:

在選擇資料庫的路上,我們遇到過哪些坑?(2)

效能表現提升了八倍。上述 GraphAware 的文章深入詳細地解釋了這一概念。

6. 優化效能

EXPLAINPROFILE 絕對是你的良師益友。別擔心 Java API,而查詢規劃程式還很年輕,在許多情況下都比 Cypher 要快。如果你要設定基準,一定要以溫備份資料庫設定基準。這樣就能載入 Neo4j 的資料庫快取。

7. 一定要交流!

Neo4j 擁有強大的支援社群,包括谷歌論壇、Slack 協作頻道、Stack Overflow 網站和非常出色的支援團隊

8. 在工具欄裡新增下面的程式碼

藉助下面的樣板程式碼,可以檢查資料庫中的每個節點並修復所有問題。這一示例有時會抓取關係,但你也可以對節點或其他限定條件進行同樣的操作。

不管怎樣,它都能事務性地依次通過資料庫中的所有節點。在本例中,每個事務是 90000 次操作,如果有需要,還可以批量更改整個資料庫:

在選擇資料庫的路上,我們遇到過哪些坑?(2)

本文系 OneAPM 工程師整理呈現。OneAPM 能為您提供端到端的應用效能解決方案,我們支援所有常見的框架及應用伺服器,助您快速發現系統瓶頸,定位異常根本原因。分鐘級部署,即刻體驗,效能監控從來沒有如此簡單。想閱讀更多技術文章,請訪問 OneAPM 官方技術部落格

本文轉自 OneAPM 官方部落格

原文地址:https://dzone.com/articles/from-good-to-graph-choosing-the-right-database

相關文章