Neo4j入門詳解
項目中某種特殊的場景,使用圖形數據庫比較有獨特的優勢。所以經過一個多月的奮戰終於把項目上線了。本次使用上了圖形數據庫是neo4j社區版,因為數據量不到一個億,只是關系比較復雜所以社區版基本上“夠用”。后續貨陸續分享,我對neo4j 社區版高可用相關方面的總結(探活,監控告警,熱備,控制台等)
本次將一些neo4j 的一些入門基礎知識,做一次項目后的整理總結(ps : 有些知識點從其他帖子cp 而來)。
Neo4j簡介
Neo4j是一個高性能的NOSQL圖形數據庫,它將結構化數據存儲在網絡上而不是表中。它是一個嵌入式的、基於磁盤的、具備完全的事務特性的Java持久化引擎,但是它將結構化數據存儲在網絡(從數學角度叫做圖)上而不是表中。Neo4j也可以被看作是一個高性能的圖引擎,該引擎具有成熟數據庫的所有特性。程序員工作在一個面向對象的、靈活的網絡結構下,而不是嚴格、靜態的表中。但是他們可以享受到具備完全的事務特性、企業級的數據庫的所有好處。Neo4j因其嵌入式、高性能、輕量級等優勢,越來越受到關注。
現實中很多數據都是用圖來表達的,比如社交網絡中人與人的關系、地圖數據、或是基因信息等等。RDBMS並不適合表達這類數據,而且由於海量數據的存在,讓其顯得捉襟見肘。NoSQL數據庫的興起,很好地解決了海量數據的存放問題,圖數據庫也是NoSQL的一個分支,相比於NoSQL中的其他分支,它很適合用來原生表達圖結構的數據。
通常來說,一個圖數據庫存儲的結構就如同數據結構中的圖,由頂點和邊組成。
Neo4j是圖數據庫中一個主要代表,其開源,且用Java實現(需安裝JDK)。經過幾年的發展,已經可以用於生產環境。其有兩種運行方式,一種是服務的方式,對外提供REST接口;另外一種是嵌入式模式,數據以文件的形式存放在本地,可以直接對本地文件進行操作。
Neo4j分三個版本:社區版(community)、高級版(advanced)和企業版(enterprise)。社區版是基礎,本文主要對其作出介紹,它使用的是GPLv3協議,這意味着修改和使用其代碼都需要開源,但是這是建立在軟件分發的基礎上,如果使用Neo4j作為服務提供,而不分發軟件,則不需要開源。這實際上是GPL協議本身的缺陷。高級版和企業版建立在社區版的基礎上,但多出一些高級特性。高級版包括一些高級監控特性,而企業版則包括在線備份、高可用集群以及高級監控特性。要注意它們使用了AGPLv3協議,也就是說,除非獲得商業授權,否則無論以何種方式修改或者使用Neo4j,都需要開源。
設計理念
Neo4j的設計動機是為了更好地同時也更高效地描述實體之間的關系。在現實生活中,每一個實體都於周圍的其他實體有着千絲萬縷的關系,這些關系里面所存儲的信息甚至要大於身體本身的屬性。然后傳統的關系型數據庫更注重刻畫實體內部的屬性,實體與實體之間的關系通常都是利用外鍵來實現。所以在求解關系的時候通常需要join操作,而join操作通常又是耗時的。互聯網尤其是移動互聯網的爆發式增長本來就使得傳統關系型數據庫不堪重負,再加上諸如社交網絡等應用對於關系的高需求,可以說關系型數據庫已經是毫無優勢。而圖數據庫作為重點描述數據之間關系的數據庫應運而生,成為了NoSQL中非常重要的一部分。而Neo4j正是圖數據庫中最為優秀的之一
Neo4j特點
所用語言: Java特點:基於關系的圖形數據庫 使用許可: GPL,其中一些特性使用 AGPL/商業許可 協議: HTTP/REST(或嵌入在 Java中) 可獨立使用或嵌入到 Java應用程序 圖形的節點和邊都可以帶有元數據 很好的自帶web管理功能 使用多種算法支持路徑搜索 使用鍵值和關系進行索引為讀操作進行優化 支持事務(用 Java api) 使用 Gremlin圖形遍歷語言支持 Groovy腳本 支持在線備份,高級監控及高可靠性支持使用 AGPL/商業許可
Neo4j相關特性
數據模型
Neo4j被稱為property graph,除了頂點(Node)和邊(Relationship,其包含一個類型),還有一種重要的部分——屬性。無論是頂點還是邊,都可以有任意多的屬性。屬性的存放類似於一個hashmap,key為一個字符串,而value必須是Java基本類型、或者是基本類型數組,比如說String、int或者int[]都是合法的。
索引
Neo4j支持索引,其內部實際上通過Lucene實現。
事務
Neo4j完整支持事務,即滿足ACID性質。
ACID是以下四個事務特性的縮寫:
- 原子性
一個事務的所有工作要么都(成功)執行,要么都不執行。不會發生只執行一部分的情況。
比如說,一個事務開始更新100行記錄,但是在更新了20行之后(因為某種原因)失敗了,那么此時數據庫會回滾(撤銷)對那20條記錄的修改。
- 一致性
事務將數據庫從一個一致性狀態帶入另一個一致性狀態。
比如說,在一個銀行事務(在描述關系數據庫事務的特性時,基本上都是用銀行事務來作為描述對象的)中,需要從存儲賬戶扣除款項,然后在支付賬戶中增加款項。
如果在這個中轉的過程發生了失敗,那么絕對不能讓數據庫只執行其中一個賬戶的操作,因為這樣會導致數據處於不一致的狀態(這樣的話,銀行的賬目上,借貸就不平衡了)。
- 隔離性
這個特性是說,直到事務結束時(commit/rollback),其他事務(或者會話)對此事務所操作的數據都不可見(但並不是說其他會話的讀取會被阻塞)。
比如說,一個用戶正在修改hr.employees表,但是沒有提交,那么其他用戶在這個修改沒有提交之前是看不到這個修改的。
- 永久性
被提交的更改會永久地保存到數據庫中(並不是說以后就不可以修改)。
事務提交之后,數據庫必須通過“恢復機制”來確保事務更改的數據不會丟失。
遍歷和查詢
遍歷是圖數據庫中的主要查詢方式,所以遍歷是圖數據中相當關鍵的一個概念。可以用兩種方式來進行遍歷查詢:第一種是直接編寫Java代碼,使用Neo4j提供的traversal框架;第二種方式是使用Neo4j提供的描述型查詢語言,Cypher。
圖算法
Neo4j實現的三種圖算法:最短路徑(最少數目的關系)、Dijkstra算法(解決有向圖中任意兩個頂點之間的最短路徑問題)以及A*算法(是解決靜態路網中求解最短路最有效的方法)。
嵌入式可擴展
Neo4j是一個嵌入式,基於磁盤的,支持完整事務的Java持久化引擎,它在圖像中而不是表中存儲數據。Neo4j提供了大規模可擴展性,在一台機器上可以處理數十億節點、關系、屬性的圖像,可以擴展到多台機器並行運行。相對於關系數據庫來說,圖形數據庫善於處理大量復雜、互連接、低結構化的數據,這些數據變化迅速,需要頻繁的查詢——在關系數據庫中,這些查詢會導致大量的表連接,因此會產生性能上的問題。Neo4j重點解決了擁有大量連接的傳統RDBMS在查詢時出現的性能衰退問題。通過圍繞圖形進行數據建模,Neo4j會以相同的速度遍歷節點與邊,其遍歷速度與構成圖形的數據量沒有任何關系。
Neo4j與傳統數據庫的區別
Neo4j | RDBMS |
---|---|
允許對數據的簡單且多樣的管理 | 高度結構化的數據 |
數據添加和定義靈活,不受數據類型和數量的限制,無需提前定義 | 表格schema需預定義,修改和添加數據結構和類型復雜,對數據有嚴格的限制 |
常數時間的關系查詢操作 | 關系查詢操作耗時 |
提出全新的查詢語言cypher,查詢語句更加簡單 | 查詢語句更為復雜,尤其涉及到join或union操作時 |
最后再以下面兩張圖來展示一下兩者在查詢關系時的區別:
RDBMS
Neo4j
Neo4j集群模式運行原理
一個Neo4J HA集群的協作運行,協調行為是通過zookeeper完成的。2.0以后基於Paxos協議開發了自己的集群協調機制。
當一個Neo4j HA實體開啟時將去連接協調器服務(zookeeper)注冊其本身並詢問“誰是主機(master)?”。如果某個機器是主機,新的實體將以從機(slaver)開啟並連接到主機(master)。如果機器開啟時為第一個注冊或者通過主機選擇算法應該成為主機,將會作為主機開啟。
當從一個從機上執行一個寫入的事務時,每個寫入操作將與主機同步(主機與從機將被鎖定)。當事務提交時首先存在於主機上。當主機事務提交成功,從機上的事務也會被提交。為確保一致性,在執行寫入操作前從機與主機同步必須是最新的。這是建立主機與從機之間的通訊協議,所以如果需要,更新將會自動發生。
可以通過在包含ha.slave_coordinator_update_mode=none配置參數的配置文件中將數據庫實體設置成只做為從機。此實體雖然在系統故障恢復選擇時將不可能再成為主機,然而此從機的行為與其他所有從機都一樣,含有永久寫入到主機的能力。
當從主機上執行寫入操作,它將與在普通的嵌入模式中執行一樣。此時主機將不會推送更新消息到從機。相反,從機可以配置一個拉取消息的時間間隔。沒有選舉,更新操作僅僅只會發生在從機上,任何時候都將同步一個寫入到主機。
將所有寫入操作通過從機執行的好處是數據將被復制到兩台機器上。這是建議的,避免當新選主機時可能造成回滾失敗。
當某台neo4j數據庫服務不可用時,協調器(coordinator)將探測到並從集群中刪除掉。當主機當機時,新的主機將自動被選擇出來。一般地,一個新的主機被選定並在幾秒鍾內啟動,在這段時間將不會執行任何寫入操作(寫入將拋出異常)。當某台機器從故障中恢復了,將會被自動重新連接到集群中。當沒有得到其他任何機器的備份的舊的主機改變時, 是唯一不確定的。如果新的主機被選擇並在舊的主機恢復前執行改變,將會有兩個不同版本的數據。舊主機將移除分支數據庫並從新主機下載一個全版本的數據。
Ø 所有這些可以歸納如下:
Ø 從機可以處理寫入事務。
Ø 更新相對從機最終將會一致。
Ø Neo4j HA 是一個容錯並能繼續執行從x台機器到單獨一台機器(基於zookeeper設置)。
Ø 在寫入操作上從機將自動同步到主機。
Ø 當主機故障時新的主機將自動選出。
Ø 當任何導致運行中斷的錯誤(網絡、維護)解決時當台機器將會自動被重新連接到集群中。
Ø 事務的原子性、持久性和一致性並最終會廣播到其他從機上。
Ø 主機故障了,所有正在運行寫入事務將會被回滾,主機選舉時任何寫入操作都不能執行。
Ø 讀取操作高度可用。
Neo4j優缺點
優點:
-
數據的插入,查詢操作很直觀,不用再像之前要考慮各個表之間的關系。
-
提供的圖搜索和圖遍歷方法很方便,速度也是比較快的。
-
更快的數據庫操作。當然,有一個前提條件,那就是數據量較大,在MySql中存儲的話需要許多表,並且表之間聯系較多(即有不少的操作需要join表)。
缺點:
-
當數據過大時插入速度可能會越來越慢。.
-
超大節點。當有一個節點的邊非常多時(常見於大V),有關這個節點的操作的速度將大大下降。這個問題很早就有了,官方也說過會處理,然而現在仍然不能讓人滿意。
-
提高數據庫速度的常用方法就是多分配內存,然而看了官方操作手冊,貌似無法直接設置數據庫內存占用量,而是需要計算后為其”預留“內存…
注:鑒於其明顯的優缺點,Neo4j適合存儲”修改較少,查詢較多,沒有超大節點“的圖數據。
應用場景
適用於圖形一類數據。這是 Neo4j與其他nosql數據庫的最顯著區別
例如:社會關系,公共交通網絡,地圖及網絡拓譜。
Neo4j不適用於:
-
記錄大量基於事件的數據(例如日志條目或傳感器數據)
-
對大規模分布式數據進行處理,類似於Hadoop
-
二進制數據存儲
-
適合於保存在關系型數據庫中的結構化數據
Neo4j安裝部署
Neo4j有兩種訪問模式:服務器模式和嵌入模式。在這里咱們只單純介紹一下服務器安裝模式。注:僅有企業付費版支持HA模式,免費試用30天。
Windows服務安裝
-
到官網下載對應版本的Neo4j安裝包
-
將安裝包放到指定的目錄下
-
NEO4J_HOME配置
-
運行:bin\Neo4j.bat install
-
查詢服務狀態:bin\Neo4j.bat status
-
開啟服務:bin\Neo4j.bat start
-
停止服務:bin\Neo4j.bat stop
-
卸載命令:bin\Neo4j.bat remove
注:如果webadmin不工作請嘗試禁用防火牆。
運行Neo4j后,在瀏覽器中打開網頁:http://localhost:7474(https的端口是7473), 即可進入Neo4j的圖形操作界面,在里面可以直接操作數據庫,也可以查看數據庫的狀態。
頁面頂端可以直接寫Cypher語句並運行。右側則顯示一些數據庫的狀態以及提供一部分操作,包括:
-
Database Information。數據庫信息。節點類別,邊的類別,屬性(包括節點的屬性和邊的屬性)。
-
Favorites。寫好的基本數據庫語句,包括創建節點,查詢節點個數,邊個數等。創建示例圖。查看數據庫的狀態。
-
Documentation。各種官方文檔。
-
Neo4j Browser Sync。清空本地數據庫。與雲端數據庫同步。
-
Browser Settings。圖形操作界面的設置。
Neo4j集群模式介紹
在了解了如何使用Neo4J之后,下一步要考慮的就是如何通過搭建一個Neo4J集群來提供一個具有高可用性,高吞吐量的解決方案了。首先您要知道的是,和其它NoSQL數據庫所提供的近乎無限的橫向擴展能力相比,Neo4J集群實際上是有一定限制的。為了能更好地理解這些限制,就讓我們首先看一看Neo4J集群的架構以及它到底是如何工作的:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-D6Mm3w01-1582473468275)(file:///C:/Users/User/AppData/Local/Temp/msohtmlclip1/01/clip_image006.jpg)]
上圖展示了一個由三個Neo4J結點所組成的Master-Slave集群。通常情況下,每個Neo4J集群都包含一個Master和多個Slave。該集群中的每個Neo4J實例都包含了圖中的所有數據。這樣任何一個Neo4J實例的失效都不會導致數據的丟失。集群中的Master主要負責數據的寫入,接下來Slave則會將Master中的數據更改同步到自身。如果一個寫入請求到達了Slave,那么該Slave也將會就該請求與Master通信。此時該寫入請求將首先被Master執行,再異步地將數據更新到各個Slave中。所以在上圖中,您可以看到表示數據寫入方式的紅線有從Master到Slave,也有從Slave到Master,但是並沒有從Slave到Slave。而所有這一切都是通過Transaction Propagation組成來協調完成的。
有些讀者可能已經注意到了:Neo4J集群中數據的寫入是通過Master來完成的,那是不是Master會變成系統的寫入瓶頸呢?答案是幾乎不會。首先是圖數據修改的復雜性導致其並不會像棧,數組等數據類型那樣容易被修改。在修改一個圖的時候,我們不但需要修改圖結點本身,還要維護各個關系,本身就是一個比較復雜的過程,對用戶而言也是較難理解的。因此對圖所進行的操作也常常是讀比寫多很多。同時Neo4J內部還有一個寫隊列,可以用來暫時緩存向Neo4J實例的寫入操作,從而使得Neo4J能夠處理突然到來的大量寫入操作。而在最壞的情況就是Neo4J集群需要面對持續的大量的寫入操作。在這種情況下,我們就需要考慮Neo4J集群的縱向擴展了,因為此時橫向擴展無益於解決這個問題。
反過來,由於數據的讀取可以通過集群中的任意一個Neo4J實例來完成,因此Neo4J集群的讀吞吐量可以在理論上做到隨集群中Neo4J實例的個數線性增長。例如如果一個擁有5個結點的Neo4J集群可以每秒響應500個讀請求,那么再添加一個結點就可以將其擴容為每秒響應600個讀請求。
但在請求量非常巨大而且訪問的數據分布非常隨機的情況下,另一個問題就可能發生了,那就是Cache-Miss。Neo4J內部使用一個緩存記錄最近所訪問的數據。這些緩存數據會保存在內存中以便快速地響應數據讀取請求。但是在請求量非常巨大而且所訪問數據分布隨機的情況下,Cache-Miss將會持續地發生,使得每次對數據的讀取都要經過磁盤查找來完成,從而大大地降低了Neo4J實例的運行效率。而Neo4J所提供的解決方案被稱為Cache-based Sharding。簡單地說,就是使用同一個Neo4J實例來響應一個用戶所發送的所有需求。其背后的原理也非常簡單,那就是同一個用戶在一段時間內所訪問的數據常常是類似的。因此將這個用戶的一系列數據請求發送到同一個Neo4J服務器實例上可以很大程度上降低發生Cache-Miss的概率。
Neo4J數據服務器中的另一個組成Cluster Management則用來負責同步集群中各個實例的狀態,並監控其它Neo4J結點的加入和離開。同時其還負責維護領導選舉結果的一致性。如果Neo4J集群中失效的結點個數超過了集群中結點個數的一半,那么該集群將只接受讀取操作,直到有效結點重新超過集群結點數量的一半。
在啟動時,一個Neo4J數據庫實例將首先嘗試着加入由配置文件所標明的集群。如果該集群存在,那么它將作為一個Slave加入。否則該集群將被創建,並且其將被作為該集群的Master。
如果Neo4J集群中的一個Neo4J實例失效了,那么其它Neo4J實例會在短時間內探測到該情況並將其標示為失效,直到其重新恢復到正常狀態並將數據同步到最新。這其中有一個特殊情況,那就是Master失效的情況。在該情況下,Neo4J集群將會通過內置的Leader選舉功能選舉出新的Master。
在Cluster Management組成的幫助下,我們還可以創建一個Global Cluster。其擁有一個Master Cluster以及多個Slave Cluster。該集群組建方式允許Master Cluster和Slave Cluster處於不同區域的服務集群中。這樣就可以允許服務的用戶訪問距離自己最近的服務。和Neo4J集群中的Master及Slave實例的關系類似,數據的寫入通常都是在Master Cluster中進行,而Slave Cluster將只負責提供數據讀取服務。
系統要求
內存限制了圖數據庫的大小,磁盤I/O限制了讀寫的性能。
中央處理器
性能通常是消耗在創建大圖數據庫的內存或者I/O上,以及計算適合內存的圖數據庫。
最小要求
Intel 486
推薦配置
Intel Core i7
內存
最小要求
1GB
推薦配置
4-8GB
磁盤
最小要求
SCSI, EIDE
推薦配置
SSD w/ SATA
文件系統
最小要求
ext3 (或者更簡單的)
推薦配置
ext4, ZFS
軟件
Neo4j是基於Java開發的。
Java
1.6+
操作系統
Linux, Windows XP, Mac OS X
Neo4j的各個版本(英文的懶得翻譯了)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-hGJUSN8Y-1582473468275)(file:///C:/Users/User/AppData/Local/Temp/msohtmlclip1/01/clip_image008.jpg)]
Linux服務安裝
-
下載對應版本的tar包到相應的目錄
-
配置NEO4J_HOME然后進入目錄中
-
執行:sudo ./bin/neo4j install
-
執行查看狀態命令:service neo4j-service status
-
執行啟動命令:service neo4j-service start
-
執行結束命令:service neo4j-service stop
注:在安裝過程中你將會被要求設定用戶名和密碼並指定數據源文件的存儲路徑。
安裝詳情請參照《neo4j 社區版搭建教程》
Neo4j服務器配置
服務器首要的配置文件是:conf/neo4j-server.properties
默認日志服務配置:conf/log4j.properties
低性能配置參數文件:conf/neo4j.properties
守護進程配置文件:conf/neo4j-wrapper.properties,怕翻譯不准確故下附原文。
(Configuraion of the deamonizing wrapper are found in conf/neo4j-wrapper.properties)
重要的配置參數
主配置文件的服務器可以發現在 conf/neo4j-server.properties。此文件包含幾個重要的設置,並且雖然默認設置是明智管理員可能會選擇進行更改 (特別是對端口設置)。
- 設置硬盤數據庫存儲目錄:org.neo4j.server.database.location=data/graph.db
注:Windows環境中應配置絕對路徑:“c:/data/db”
- 指明支持數據、管理、UI接入的http(HTTPS的為7473)服務端口:org.neo4j.server.webserver.port=7474
指明web服務的客戶端接受模式(默認的是127.0.0.1和localhost)
- #allow any client to connect
org.neo4j.server.webserver.address=0.0.0.0
-
設置REST數據API訪問數據庫時的相對路徑:org.neo4j.server.webadmin.data.uri=/db/data/
-
設置在使用webadmin 工具時administration API的管理URI的相對路徑org.neo4j.server.webadmin.management.uri=/db/manage
-
Force the server to use IPv4 network addresses, in conf/neo4j-wrapper.conf under the section Java Additional Parameters add a new paramter: wrapper.java.additional.3=-Djava.net.preferIPv4Stack=true 強制服務器使用IPv4地址
-
低性能調節參數應當被如下的設置明確指定:org.neo4j.server.db.tuning.properties=neo4j.properties
注:如果沒有設置服務器會在相同的路徑下尋找neo4j.properties充當neo4j-server.properties如果既沒有設置這個參數,相同的路徑下也不存在這個文件,服務會在日志中作出警報,隨后在運行時服務器會安裝默認設置調節自身。
- 關掉顯示器的日志輸出:java.util.logging.ConsoleHandler.level=OFF
編輯conf/neo4j-server.properties啟用http loging: org.neo4j.server.http.log.enabled=true
org.neo4j.server.http.log.config=conf/neo4j-http-logging.xml
-
如果你需要能從外部主機訪問,請在 conf/neo4j-server.properties 中設置 org.neo4j.server.webserver.address=0.0.0.0 來啟用。
-
取消密碼登錄
-
配置自動索引,配置完成后重啟服務(貌似新版本中已經沒有這個功能,使用過程中一般手動指定)。
Enable auto-indexing for nodes, default is false.
node_auto_indexing=true
The node property keys to be auto-indexed, if enabled.
node_keys_indexable=name,ki
Enable auto-indexing for relationships, default is false.
relationship_auto_indexing=true
The relationship property keys to be auto-indexed, if enabled.
relationship_keys_indexable=name,ki
Neo4j開發指南
查看PPT文件。
Neo4j核心之cypher語法
Cypher介紹
“Cypher”是一個描述性的圖形查詢語言,允許不必編寫圖形結構的遍歷代碼對圖形存儲有表現力和效率的查詢。Cypher還在繼續發展和成熟,這也就意味着有可能會出現語法的變化。同時也意味着作為組件沒有經歷嚴格的性能測試。
Cypher設計的目的是一個人類查詢語言,適合於開發者和在數據庫上做點對點模式(ad-hoc)查詢的專業操作人員(我認為這個很重要)。它的構念是基於英語單詞和靈巧的圖解。
Cyper通過一系列不同的方法和建立於確定的實踐為表達查詢而激發的。許多關鍵字如like和order by是受SQL的啟發。模式匹配的表達式來自於SPARQL。正則表達式匹配實現實用Scala programming language語言。
Cypher是一個申明式的語言。對比命令式語言如Java和腳本語言如Gremlin和JRuby,它的焦點在於從圖中如何找回(what to retrieve),而不是怎么去做。這使得在不對用戶公布的實現細節里關心的是怎么優化查詢。
這個查詢語言包含以下幾個明顯的部分:
-
START:在圖中的開始點,通過元素的ID或所以查找獲得。
-
MATCH:圖形的匹配模式,束縛於開始點。
-
WHERE:過濾條件。
-
RETURN:返回所需要的。
操作符
Cypher中的操作符有三個不同種類:數學,相等和關系。
數學操作符有+,-,*,/和%。當然只有+對字符有作用。
等於操作符有=,<>,<,>,<=,>=。
因為Neo4j是一個模式少的圖形數據庫,Cypher有兩個特殊的操作符?和!。
有些是用在屬性上,有些事用於處理缺少值。對於一個不存在的屬性做比較會導致錯誤。為替代與其他什么做比較時總是檢查屬性是否存在,在缺失屬性時問號將使得比較總是返回true,感嘆號使得比較總是返回false。
WHEREn.prop? = “foo”
這個斷言在屬性缺失情況下將評估為true。
WHEREn.prop! = “foo”
這個斷言在屬性缺失情況下將評估為false。
警告:在同一個比較中混合使用兩個符號將導致不可預料的結果。
參數
Cypher支持帶參數的查詢。這允許開發者不需要必須構建一個string的查詢,並且使得Cypher的查詢計划的緩存更容易。
參數可以在where子句,start子句的索引key或索引值,索引查詢中作為節點/關系id的引用。
以下是幾個在java中使用參數的示例:
節點id參數
Map<String, Object> params = new HashMap<String, Object>();
params.put( “id”, 0 );
ExecutionResult result = engine.execute( “start n=node({id}) return n.name”, params );
節點對象參數
Map<String, Object> params = new HashMap<String, Object>();
params.put( “node”, andreasNode );
ExecutionResult result = engine.execute( “start n=node({node}) return n.name”, params );
多節點id參數
Map<String, Object> params = new HashMap<String, Object>();
params.put( “id”, Arrays.asList( 0, 1, 2 ) );
ExecutionResult result = engine.execute( “start n=node({id}) return n.name”, params );
字符串參數
Map<String, Object> params = new HashMap<String, Object>();
params.put( “name”, “Johan” );
ExecutionResult result = engine.execute( “start n=node(0,1,2) where n.name = {name} return n”, params );
索引鍵值參數
Map<String, Object> params = new HashMap<String, Object>();
params.put( “key”, “name” );
params.put( “value”, “Michaela” );
ExecutionResult result = engine.execute( “start n=node:people({key} = {value}) return n”, params );
索引查詢參數
Map<String, Object> params = new HashMap<String, Object>();
params.put( “query”, “name:Andreas” );
ExecutionResult result = engine.execute( “start n=node:people({query}) return n”, params );
l SKIP 與LIMIT * 的數字參數
Map<String, Object> params = new HashMap<String, Object>();
params.put( “s”, 1 );
params.put( “l”, 1 );
ExecutionResult result = engine.execute( “start n=node(0,1,2) return n.name skip {s} limit {l}”, params );
l 正則表達式參數
Map<String, Object> params = new HashMap<String, Object>();
params.put( “regex”, “.h.” );
ExecutionResult result = engine.execute( “start n=node(0,1,2) where n.name =~ {regex} return n.name”, params );
標識符
當你參考部分的模式時,需要通過命名完成。定義的不同的命名部分就被稱為標識符。
如下例中:
START n=node(1) MATCH n–>b RETURN b
標識符為n和b。
標識符可以是大寫或小些,可以包含下划線。當需要其他字符時可以使用符號。對於屬性名的規則也是一樣。
注解
可以在查詢語句中使用雙斜杠來添加注解。如:
START n=node(1) RETURN b //這是行結束注釋
START n=node(1) RETURN b
START n=node(1) WHERE n.property = “//這部是一個注釋” RETURN b
Start
每一個查詢都是描述一個圖案(模式),在這個圖案(模式)中可以有多個限制點。一個限制點是為模式匹配的從開始點出發的一條關系或一個節點。可以通過id或索引查詢綁定點。
通過id綁定點
通過node(*)函數綁定一個節點作為開始點
查詢:
START n=node(1)
RETURN n
返回引用的節點。
通過id綁定關系
可以通過relationship()函數綁定一個關系作為開始點。也可以通過縮寫rel()。
查詢:
START r=relationship(0)
RETURN r
Id為0的關系將被返回
通過id綁定多個節點
選擇多個節點可以通過逗號分開。
查詢:
START n=node(1, 2, 3)
RETURN n
所有節點
得到所有節點可以通過星號(*),同樣對於關系也適用。
查詢:
START n=node(*)
RETURN n
這個查詢將返回圖中所有節點。
通過索引查詢獲取節點
如果開始節點可以通過索引查詢得到,可以如此來寫:
node:index-name(key=”value”)。在此列子中存在一個節點索引叫nodes。
查詢:
START n=node:nodes(name = “A”)
RETURN n
索引中命名為A的節點將被返回。
通過索引查詢獲取關系
如果開始點可以通過索引查詢得到,可以如此做:
Relationship:index-name(key=”value”)。
查詢:
START r=relationship:rels(property =“some_value”)
RETURN r
索引中屬性名為”some_value”的關系將被返回。
多個開始點
有時需要綁定多個開始點。只需要列出並以逗號分隔開。
查詢:
START a=node(1), b=node(2)
RETURN a,b
A和B兩個節點都將被返回。
Match
在一個查詢的匹配(match)部分申明圖形(模式)。模式的申明導致一個或多個以逗號隔開的路徑(path)。
節點標識符可以使用或者不是用圓括號。使用圓括號與不使用圓括號完全對等,如:
MATCH(a)–>(b) 與 MATCH a–>b 匹配模式完全相同。
模式的所有部分都直接或者間接地綁定到開始點上。可選關系是一個可選描述模式的方法,但在真正圖中可能沒有匹配(節點可能沒有或者沒有此類關系時),將被估值為null。與SQL中的外聯結類似,如果Cypher發現一個或者多個匹配,將會全部返回。如果沒有匹配,Cypher將返回null。
如以下例子,b和p都是可選的病都可能包含null:
START a=node(1) MATCH p = a-[?]->b
START a=node(1) MATCH p = a-[*?]->b
START a=node(1) MATCH p = a-[?]->x–>b
START a=node(1), x=node(100) MATCH p = shortestPath( a-[*?]->x )
相關節點
符號—意味着相關性,不需要關心方向和類型。
查詢:
START n=node(3)
MATCH (n)–(x)
RETURN x
所有與A相關節點都被返回。
接出關系(Outgong relationship)
當對關系的方向感興趣時,可以使用–>或<–符號,如:
查詢:
START n=node(3)
MATCH (n)–>(x)
RETURN x
所有A的接出關系到達的節點將被返回.
定向關系和標識符
如果需要關系的標識符,為了過濾關系的屬性或為了返回關系,可如下例使用標識符。
查詢:
START n=node(3)
MATCH (n)-[r]->()
RETURN r
所有從節點A接出的關系將被返回。
通過關系類型匹配
當已知關系類型並想通過關系類型匹配時,可以通過冒號詳細描述。
查詢:
START n=node(3)
MATCH (n)-[:BLOCKS]->(x)
RETURN x
返回A接出關系類型為BLOCKS的節點。
通過關系類型匹配和使用標識符
如果既想獲得關系又要通過已知的關系類型,那就都添加上,如:
查詢:
START n=node(3)
MATCH (n)-[r:BLOCKS]->()
RETURN r
所有從A接出的關系為BLOCKS的關系都被返回。
帶有特殊字符的關系類型
有時候數據庫中有非字母字符類型,或有空格在內時,使用單引號。
查詢:
START n=node(3)
MATCH (n)-[r:TYPE WITH SPACE IN IT]->()
RETURN r
返回類型有空格的關系。
多重關系
關系可以通過使用在()—()多個語句來表達,或可以串在一起。如下:
查詢:
START a=node(3)
MATCH (a)-[:KNOWS]->(b)-[:KNOWS]->©
RETURN a,b,c
路徑中的三個節點。
可變長度的關系
可變數量的關系->節點可以使用-[:TYPE*minHops…maxHops]->。
查詢:
START a=node(3), x=node(2, 4)
MATCH a-[:KNOWS*1…3]->x
RETURN a,x
如果在1到3的關系中存在路徑,將返回開始點和結束點。
在可變長度關系的關系標識符
當連接兩個節點的長度是可變的不確定的時,可以使用一個關系標識符遍歷所有關系。
查詢:
START a=node(3), x=node(2, 4)
MATCH a-[r:KNOWS*1…3]->x
RETURN r
如果在1到3的關系中存在路徑,將返回開始點和結束點。
零長度路徑
當使用可變長度路徑,可能其路徑長度為0,這也就是說兩個標識符指向的為同一個節點。如果兩點間的距離為0,可以確定這是同一個節點。
查詢:
START a=node(3)
MATCH p1=a-[:KNOWS0…1]->b, p2=b-[:BLOCKS0…1]->c
RETURN a,b,c, length(p1), length(p2)
這個查詢將返回四個路徑,其中有些路徑長度為0.
可選關系
如果關系為可選的,可以使用問號表示。與SQL的外連接類似。如果關系存在,將被返回。如果不存在在其位置將以null代替。
查詢:
START a=node(2)
MATCH a-[?]->x
RETURN a,x
返回一個節點和一個null,因為這個節點沒有關系。
可選類型和命名關系
通過一個正常的關系,可以決定哪個標識符可以進入,那些關系類型是需要的。
查詢:
START a=node(3)
MATCH a-[r?:LOVES]->()
RETURN a,r
返回一個節點和一個null,因為這個節點沒有關系。
可選元素的屬性
返回可選元素上的屬性,null值將返回null。
查詢:
START a=node(2)
MATCH a-[?]->x
RETURN x, x.name
元素x在查詢中為null,所有其屬性name為null。
復雜匹配
在Cypher中,可喲通過更多復雜模式來匹配,像一個鑽石形狀模式。
查詢:
START a=node(3)
MATCH (a)-[:KNOWS]->(b)-[:KNOWS]->©,(a)-[:BLOCKS]-(d)-[:KNOWS]-©
RETURN a,b,c,d
路徑中的四個節點。
最短路徑
使用shortestPath函數可以找出一條兩個節點間的最短路徑,如下。
查詢:
START d=node(1), e=node(2)
MATCH p = shortestPath( d-[*…15]->e )
RETURN p
這意味着:找出兩點間的一條最短路徑,最大關系長度為15.圓括號內是一個簡單的路徑連接,開始節點,連接關系和結束節點。關系的字符描述像關系類型,最大數和方向在尋找最短路徑中都將被用到。也可以標識路徑為可選。
所有最但路徑
找出兩節點節點所有的最短路徑。
查詢:
START d=node(1), e=node(2)
MATCH p = allShortestPaths( d-[*…15]->e )
RETURN p
這將在節點d與e中找到兩條有方向的路徑。
命名路徑
如果想在模式圖上的路徑進行過濾或者返回此路徑,可以使用命名路徑(named path)。
查詢:
START a=node(3)
MATCH p = a–>b
RETURN p
開始節點的兩個路徑。
在綁定關系上的匹配
當模式中包含一個綁定關系時,此關系模式沒有明確的方向,Cypher將嘗試着切換連接節點的邊匹配關系。
查詢:
START a=node(3), b=node(2)
MATCH a-[?:KNOWS]-x-[?:KNOWS]-b
RETURN x
將返回兩個連接節點,一次為開始節點,一次為結束節點。
Where
如果需要從查找的數據的圖中過濾,可以在查詢語句中添加where子句。
Boolean 操作類型
可以使用boolean操作符and 和 or 或者也可以使用not()函數。
查詢:
START n=node(3, 1)
WHERE (n.age < 30 and n.name = “Tobias”) ornot(n.name = “Tobias”)
RETURN n
返回節點。
節點屬性上的過濾
查詢:
START n=node(3, 1)
WHERE n.age < 30
RETURN n
正則表達式
可以通過使用=~ /regexp/來匹配正在表達式。如下:
查詢:
START n=node(3, 1)
WHERE n.name =~ /Tob.*/
RETURN n
返回名叫Tobias的節點。
轉義正則表達式
如果在正則表達式中需要有斜杠時可以通過轉義實現。
查詢:
START n=node(3, 1)
WHERE n.name =~ /Some/thing/
RETURN n
沒有匹配的節點返回。
不分大小些正則表達式
在正則表達式前加上?i,整個正則表達式將會忽略大小寫。
查詢:
START n=node(3, 1)
WHERE n.name =~ /(?i)ANDR.*/
RETURN n
屬性name為Andres的節點將返回
關系類型上的過濾
可以match模式中通過添加具體的關系類型,但有時需要針對類型的更加高級的過濾。可以使用明確的type屬性來對比,查詢對關系類型名作一個正則比較。
查詢:
START n=node(3)
MATCH (n)-[r]->()
WHERE type® =~ /K.*/
RETURN r
關系整個以K開始的類型名都將返回。
屬性存在性
查詢:
START n=node(3, 1)
WHERE n.belt
RETURN n
如果缺失屬性默認為true
僅當屬性存在時,比較一個圖的元素的此屬性,使用允許空屬性的語法。
查詢:
START n=node(3, 1)
WHERE n.belt? = ‘white’
RETURN n
所有節點即使沒有belt屬性的 都將返回。此類比較返回為true。
如果缺失屬性默認為false
需要在缺失屬性時為false,即不想返回此屬性不存在的節點時。使用感嘆號。
查詢:
START n=node(3, 1)
WHERE n.belt! = ‘white’
RETURN n
空置null過濾
有時候需要測試值或者標識符是否為null。與sql類似使用 is null 或 not(is null x)也能起作用。
查詢:
START a=node(1), b=node(3, 2)
MATCH a<-[r?]-b
WHERE r is null
RETURN b
Tobias節點沒有鏈接上。
關系過濾
為過濾兩點間基於關系的子圖,在match子句中使用限制部分。可以描述帶方向的關系和可能的類型。這些都是有效的表達:WHERE a-→b WHERE a←-b WHERE a←[:KNOWS]-bWHERE a-[:KNOWS]-b
查詢:
START a=node(1), b=node(3, 2)
WHERE a<–b
RETURN b
Tobias節點沒有鏈接
neo4j 綜合
查詢中的返回部分,返回途中定義的感興趣的部分。可以為節點、關系或其上的屬性。
返回節點
返回一個節點,在返回語句中列出即可。
查詢:
START n=node(2)
RETURN n
返回關系
查詢:
START n=node(1)
MATCH (n)-[r:KNOWS]->©
RETURN r
返回屬性
查詢:
START n=node(1)
RETURN n.name
帶特殊字符的標識符
使用不在英語字符表中的字符,可以使用’單引號。
查詢:
START This isn’t a commonidentifier=node(1)
RETURN This isn’t a commonidentifier.<<!!__??>>`
列的別名
可以給展示出來的列名起別名。
查詢:
START a=node(1)
RETURN a.age AS SomethingTotallyDifferent
返回節點的age屬性,但重命名列名。
可選屬性
屬性在節點上可能存在也可能不存在,可以使用問號來標識標識符即可。
查詢:
START n=node(1, 2)
RETURN n.age?
如果存在age屬性,則返回,不存在則返回null。
特別的結果
DISTINCT 僅檢索特別的行,基於選擇輸出的列。
查詢:
START a=node(1)
MATCH (a)–>(b)
RETURN distinct b
返回name為B的節點,但僅為一次。
neo4j 聚合函數
聚合(Aggregation)
為集合計算數據,Cypher提供聚類功能,與SQL的group by類似。在return語句中發現的任何聚類函數,所有沒有聚類函數的列將作為聚合key使用。圖:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-twepaXSm-1582473468294)(file:///C:/Users/User/AppData/Local/Temp/msohtmlclip1/01/clip_image114.jpg)]
計數
計數(count)使用來計算行數。Count有兩種使用方法。Count(*)計算匹配的行的行數,count(<標識符>)計算標識符中非空值數。
計算節點數
計算鏈接到一個節點的節點數,可以使用count(*)。
查詢:
START n=node(2)
MATCH (n)–>(x)
RETURN n, count(*)
返回開始節點和相關節點節點數。
分組計算關系類型
計算分組了得關系類型,返回關系類型並使用count(*)計算。
查詢:
START n=node(2)
MATCH (n)-[r]->()
RETURN type®, count(*)
返回關系類型和其分組數。
計算實體數
相比使用count(*),可能計算標識符更實在。
查詢:
START n=node(2)
MATCH (n)–>(x)
RETURN count(x)
返回鏈接到開始節點上的節點數
計算非空可以值數
查詢:
START n=node(2,3,4,1)
RETURN count(n.property?)
求和(sum)
Sum集合簡單計算數值類型的值。Null值將自動去掉。如下:
查詢:
START n=node(2,3,4)
RETURN sum(n.property)
計算所有節點屬性值之和。
平均值(avg)
Avg計算數量列的平均值
查詢:
START n=node(2,3,4)
RETURN avg(n.property)
最大值(max)
Max查找數字列中的最大值。
查詢:
START n=node(2,3,4)
RETURN max(n.property)
最小值(min)
Min使用數字屬性作為輸入,並返回在列中最小的值。
查詢:
START n=node(2,3,4)
RETURN min(n.property)
聚類(COLLECT)
Collect將所有值收集到一個集合list中。
查詢:
START n=node(2,3,4)
RETURN collect(n.property)
返回一個帶有所有屬性值的簡單列。
相異(DISTINCT)
聚合函數中使用distinct來去掉值中重復的數據。
查詢:
START a=node(2)
MATCH a–>b
RETURN count(distinct b.eyes)
neo4j 高級篇
排序(Order by)
輸出結果排序可以使用order by 子句。注意,不能使用節點或者關系排序,僅僅只針對其屬性有效。
通過節點屬性排序節點
查詢:
START n=node(3,1,2)
RETURN n
ORDER BY n.name
通過多節點屬性排序節點
在order by子句中可以通過多個屬性來排序每個標識符。Cypher首先將通過第一個標識符排序,如果第一個標識符或屬性相等,則在order by中檢查下一個屬性,依次類推。
查詢:
START n=node(3,1,2)
RETURN n
ORDER BY n.age, n.name
首先通過age排序,然后再通過name排序。
倒序排列節點
可以在標識符后添加desc或asc來進行倒序排列或順序排列。
查詢:
START n=node(3,1,2)
RETURN n
ORDER BY n.name DESC
空值排序
當排列結果集時,在順序排列中null將永遠放在最后,而在倒序排列中放最前面。
查詢:
START n=node(3,1,2)
RETURN n.length?, n
ORDER BY n.length?
Skip
Skip允許返回總結果集中的一個子集。此不保證排序,除非使用了order by’子句。
跳過前三個
返回結果中一個子集,從第三個結果開始,語法如下:
查詢:
START n=node(3, 4, 5, 1, 2)
RETURN n
ORDER BY n.name
SKIP 3
前三個節點將略過,最后兩個節點將被返回。
返回中間兩個
查詢:
START n=node(3, 4, 5, 1, 2)
RETURN n
ORDER BY n.name
SKIP 1
LIMIT 2
中間兩個節點將被返回。
Limit
Limit允許返回結果集中的一個子集。
返回第一部分
查詢:
START n=node(3, 4, 5, 1, 2)
RETURN n
LIMIT 3
函數(Functions)
在Cypher中有一組函數,可分為三類不同類型:判斷、標量函數和聚類函數。
判斷
判斷為boolean函數,對給出的輸入集合做判斷並返回true或者false。常用在where子句中過濾子集。
All
迭代測試集合中所有元素的判斷。
語法:
All(標識符 in iterable where 判斷)
參數:
Ø iterable :一個集合屬性,或者可迭代的元素,或一個迭代函數。
Ø 標識符:可用於判斷比較的標識符。
Ø 判斷:一個測試所有迭代器中元素的判斷。
查詢:
START a=node(3), b=node(1)
MATCH p=a-[*1…3]->b
WHERE all(x in nodes§ WHERE x.age > 30)
RETURN p
過濾包含age〈30的節點的路徑,返回符合條件路徑中所有節點。
Any
語法:ANY(identifierin iterable WHERE predicate)
參數:
Ø Iterable(迭代器):一個集合屬性,或者可迭代的元素,或一個迭代函數。
Ø Identifier(標識符):可用於判斷比較的標識符。
Ø Predicate(判斷):一個測試所有迭代器中元素的判斷。
查詢:
START a=node(2)
WHERE any(x in a.array WHERE x = “one”)
RETURN a
None
在迭代器中沒有元素判斷將返回true。
語法:NONE(identifierin iterable WHERE predicate)
Ø Iterable(迭代器):一個集合屬性,或者可迭代的元素,或一個迭代函數。
Ø Identifier(標識符):可用於判斷比較的標識符。
Ø Predicate(判斷):一個測試所有迭代器中元素的判斷。
查詢:
START n=node(3)
MATCH p=n-[*1…3]->b
WHERE NONE(x in nodes§ WHERE x.age = 25)
RETURN p
Single
如果迭代器中僅有一個元素則返回true。
語法:SINGLE(identifierin iterable WHERE predicate)
參數:
Ø Iterable(迭代器):一個集合屬性,或者可迭代的元素,或一個迭代函數。
Ø Identifier(標識符):可用於判斷比較的標識符。
Ø Predicate(判斷):一個測試所有迭代器中元素的判斷。
查詢:
START n=node(3)
MATCH p=n–>b
WHERE SINGLE(var in nodes§ WHERE var.eyes = “blue”)
RETURN p
Scalar函數
標量函數返回單個值。
Length
使用詳細的length屬性,返回或過濾路徑的長度。
語法:LENGTH(iterable )
參數:
Ø Iterable(迭代器):一個集合屬性,或者可迭代的元素,或一個迭代函數。
查詢:
START a=node(3)
MATCH p=a–>b–>c
RETURN length§
返回路徑的長度。
Type
返回關系類型的字符串值。
語法:TYPE(relationship )
參數:
Ø Relationship:一條關系。
查詢:
START n=node(3)
MATCH (n)-[r]->()
RETURN type®
返回關系r的類型。
Id
返回關系或者節點的id
語法:ID(property-container )
參數:
Ø Property-container:一個節點或者一條關系。
查詢:
START a=node(3, 4, 5)
RETURN ID(a)
返回這三個節點的id。
Coalesce
返回表達式中第一個非空值。
語法:COALESCE(expression [, expression]* )
參數:
Ø Expression:可能返回null的表達式。
查詢:
START a=node(3)
RETURN coalesce(a.hairColour?,a.eyes?)
Iterable函數
迭代器函數返回一個事物的迭代器—在路徑中的節點等等。
Nodes
返回一個路徑中的所有節點。
語法:NODES(path )
參數:
Ø Path:路徑
查詢:
START a=node(3), c=node(2)
MATCH p=a–>b–>c
RETURN NODES§
Relationships
返回一條路徑中的所有關系。
語法:RELATIONSHIPS(path )
參數:
Ø Path:路徑
查詢:
START a=node(3), c=node(2)
MATCH p=a–>b–>c
RETURN RELATIONSHIPS§
Extract
可以使用extract單個屬性,或從關系或節點集合迭代一個函數的值。將遍歷迭代器中所有的節點並運行表達式返回結果。
語法:EXTRACT(identifier in iterable : expression )
Ø Iterable(迭代器):一個集合屬性,或者可迭代的元素,或一個迭代函數。
Ø Identifier(標識符):閉包中表述內容的標識符,這決定哪個標識符將用到。
Ø expression(表達式):這個表達式將對於迭代器中每個值運行一次,並生成一個結果迭代器。
查詢:
START a=node(3), b=node(4),c=node(1)
MATCH p=a–>b–>c
RETURN extract(n in nodes§ : n.age)
返回路徑中所有age屬性值。
Neo4j常見問題
Q:neo4j數據庫支持最大多少個節點?最大支持多少條邊?
A目前累積統計它有34.4億個節點,344億的關系,和6870億條屬性。
Q:neo4j數據庫支持的最復雜的連接是什么?(比如每個節點都與其他任何一個節點相連)
A: 可以從上面的數字得出理論的極限:它基本上就產生了262144節點和34359607296的關系圖。我們從來沒有見過這種使用情況。
Q: 在數據庫中,讀/寫性能跟節點/邊的數量有關嗎?
這個問題意味着兩個不同的問題。單次讀/寫操作不依賴數據庫的大小。不管數據庫是有10個節點還是有1千萬個都一樣。 — 然而,有一個事實是如果數據庫太大,你的內存可能無法完全緩存住它,因此,你需要頻繁的讀寫磁盤。雖然很多用戶沒有這樣大尺寸的數據庫,但有的人卻有。如果不巧你的數據庫達到了這個尺寸,你可以擴展到多台機器上以減輕緩存壓力。
neo4j數據庫支持的讀/寫並發請求最大數量是多少呢?
在並發請求上面沒有任何限制。服務器的並發量更多的是依賴於操作本身的性能(高壓寫操作,簡單讀,復雜的遍歷等等),以及使用的硬件性能。據粗略估計,在遍歷最簡單路徑時每毫秒可以達到1000次請求。在討論了指定的用戶案例后,我們能得到更好的性能優化方案。
在數據庫集群環境中數據一致性如何保證的呢?
主從復制。從服務器從主服務器拉取數據變化。拉取間隔可以在每個從服務器上進行配置,從毫秒到分鍾,根據你自己的需要來定。HA也可以通過從服務器來進行寫操作。當發生時,從服務器通過追上主服務器來被寫入,然后寫入在主從之間完成。其他從服務器做一般處理。
當在一個數據庫中發生更新操作時如何快速更新其他所有服務器呢?
拉取間隔在每個從服務器上面進行配置,從幾秒到幾分鍾不等,根據需求而定。當通過一個從服務器寫操作時,從服務器立即在寫之前與主服務器進行同步。一般情況下,讀寫加載不並影響從服務器的同步工作。一個復雜的寫操作會給從服務器的文件系統巨大壓力,與此同時,從服務器也要求拉取同步數據。實際上,我們不系統這成為一個關注的問題。
在集群環境中,在不同服務器會出現按比例延遲新增嗎?
在集群中從服務器超過10台的規模時,我們能預料到來自從服務器的大量的拉取請求會降低從服務器的性能。在集群中的寫操作才會受影響,而讀操作依然保持線性縮放。
支持在線擴展嗎?換句話說,如果我們想新加入一台服務器到集群中需要關閉所有服務器嗎?
新的從服務器在不用停止或者啟動整個集群的情況下可以被加入到一個已經存在的集群中。我們的HA協議會新增入加入的服務器。從服務器也可以簡單的通過關閉他們自己來從集群中移除。
新加入一台服務器到全部同步需要多長時間?
我們推薦在將從服務器加入之前先做一個最近的數據庫的快照。一般通過備份來完成。從服務器之需要同步最近的更新,一般情況下只會一點點時間的數據。
重啟需要多久呢?
如果重啟,你的意思是關閉集群然后再重啟它,這完全依賴與你打字的速度。一般是10秒的樣子。Neo4j的緩存不會自動預加載,而操作系統的文件系統緩存不會重置。
是否有備份恢復機制?
Neo4j 企業版提供了一個在線備份(完整備份和增量備份)功能。
是否支持跨區集群?跨區集群是否比同區集群性能更低呢?
我們有用戶在AWS上面測試了多區域部署的情況。跨地區部署在集群管理的效率和協議同步上有一定影響。集群管理大量的延遲會觸發主服務器的頻繁重選,拖慢整個集群的速度。在跨區部署支持上面以后還需大量提升。
是否有任何指定測控策略用於環境建立之類的需求?
關於這個話題我們有更深入的探討。
寫數據庫是線程安全的嗎?
不管在單服務模式還是HA模式,數據庫在更新之前都通過鎖定節點和關系來保證線程安全。從HA讀數據最好的策略是什么?
保持會話。
在response中發送返回數據,而在獨立的請求中移除需要讀回的數據。
當操作需要時,強制請求從主服務器做一個拉取數據更新操作。
對於獲取(如果不存在則創建)這中需求最好的策略是什么?
單線程模式。
如果不存在,悲觀鎖在一個普通節點上。
如果不存在,樂觀創建他,然后再檢查。
如何鎖定服務?
悲觀鎖。在讀數據時並不要求鎖。寫操作並不會阻塞讀操作。不用任何明確的鎖定操作就可以完成讀取數據操作是非常重要的。當一個節點或者屬性修改或者新增時,寫鎖定會自動完成,或者也可以通過明確的鎖設置。它常被用來提供讀取語義和保證必須的數據一致性。
數據存儲占用空間如何?
Neo4j當前並不適合存儲 BLOBs/CLOBs。節點,關系和屬性並不是保存在磁盤的同一個地方。這個特性將來會進一步介紹。數據庫索引怎么樣? Neo4j支持復雜的屬性索引。額外的索引功能超過了圖本身的索引。Lucene引擎管理獨立分頁的索引並要求一些空間來存儲一個自動索引以及管理私有索引(通過API搜索)。
我如何進行數據庫查詢?
核心 API, Traversal API, REST API, Cypher, Gremlin Neo4j使用日志(在數據丟失時可以修復丟失的數據)功能嗎? 在HA集群環境中基於主從服務器之間的寫增量來完成。
我如何提示Neo4j的性能?
采用內存映射存儲Neo4j文件,Neo4j緩存策略解釋如下:
軟索引緩存: 軟索引在GC認為需要時會被隨時清理。如果應用加載並不高時使用。
弱索引緩存: 不管GC是否找到,都會清理弱索引。如果在讀取大量數據或者遍歷操作時使用。
強索引緩存: 所有的節點和關系都會保存在內存中,JVM會阻止高加載的操作。比如半分鍾的暫停間隔。 更大的堆大小是好的,然而12G或者更大的內存對於GC是不切實際的。如果用從磁盤獲取數據做比較,用內存映射文件緩存會提供100倍性能,而用Java堆則會是1000倍。
在主從服務器直接的ACID事務。
在初始從服務器到主服務器的事務同步中,最終從主服務器到其他從服務器。用死鎖探測來完成多個從服務器事務並發支持。從一個數據完整性的角度看是完全一致的,但是必須得重多個點考慮。
獨立服務器怎么樣?
REST API是完全無狀態的,但他也可以通過批量提交來實現大量事務支持。線程池和每個socket的線程:對於獨立服務器和HA模式來說,Neo4j采用Jetty來連接線程池。(比如在HA集群中25/每節點)。
在HA環境中如何使用負載均衡?
通常一個小型服務器擴展被寫入后會返回200或404,取決於機器是否是主或從。 擴展被負載均衡服務器用來探測主從服務器設置。只寫到從服務器來確保至少在兩個地方存在提交事務。
Neo4j支持那些監控器?
Neo4j目前沒有內建的追蹤和解釋計划。JMX是用於統計和監控的主要接口。線程內容可以用於調試。
我如何導入數據到Neo4j中?
Neo4j批量插入用於初始化一個數據庫。在批量插入后,存儲的內容可以用與嵌入模式或者HA環境。直接跟傳統SQL服務器直接的數據交換目前沒有官方支持。
參考資料:
- 《neo4j權威指南》