1. 環境搭建
正好最近同學有一台阿里雲服務器借我玩,就嘗試着在服務器上搭了Neo4j。
環境:CentOS Linux release 7.4.1708 (Core)
安裝Java
安裝Neo4j需要Java環境。並且需要jdk1.8,所以低版本需要卸載重裝。
去 官網 復制下載鏈接,然后到命令行找一個目錄下載:
wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u151-b12/e758a0de34e24606bca991d704f6dcbf/jdk-8u151-linux-x64.rpm"
(開始直接wget下載,然后解壓一直出錯,最后發現下載的是...HTML document,真的是尷尬,然后找到了這個下載方法)
安裝:sudo rpm -ivh jdk-8u151-linux-x64.rpm
查看安裝版本:java -version
當看到
java version "1.8.0_151"
Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)
Java安裝成功!
(我真的是...裝了好久...蠢哭)
安裝Neo4j
官網有 教程 安裝社區版。
[root@neo4j]# wget http://debian.neo4j.org/neotechnology.gpg.key
[root@neo4j]# rpm --import neotechnology.gpg.key
[root@neo4j]# cat <<EOF > /etc/yum.repos.d/neo4j.repo
> [neo4j]
> name=Neo4j Yum Repo
> baseurl=http://yum.neo4j.org/stable
> enabled=1
> gpgcheck=1
> EOF
[root@neo4j]# yum install neo4j -y
嗯。。下載速度比較超級慢,等了十多分鍾。
查看安裝版本:
[root@neo4j]# neo4j version
OpenJDK 64-Bit Server VM warning: If the number of processors is expected to increase from one, then you should configure the number of parallel GC threads appropriately using -XX:ParallelGCThreads=N
neo4j 3.3.0
已經安裝成功,版本為3.3.0。
啟動Neo4j服務
啟動:neo4j console
Active database: graph.db
Directories in use:
home: /var/lib/neo4j
config: /etc/neo4j
logs: /var/log/neo4j
plugins: /var/lib/neo4j/plugins
import: /var/lib/neo4j/import
data: /var/lib/neo4j/data
certificates: /var/lib/neo4j/certificates
run: /var/run/neo4j
Starting Neo4j.
OpenJDK 64-Bit Server VM warning: If the number of processors is expected to increase from one, then you should configure the number of parallel GC threads appropriately using -XX:ParallelGCThreads=N
2017-10-31 15:50:26.178+0000 WARN dbms.directories.certificates is deprecated.
2017-10-31 15:50:26.221+0000 INFO ======== Neo4j 3.3.0 ========
2017-10-31 15:50:26.279+0000 INFO Starting...
2017-10-31 15:50:28.849+0000 INFO Bolt enabled on 127.0.0.1:7687.
2017-10-31 15:50:34.056+0000 INFO Started.
2017-10-31 15:50:35.693+0000 INFO Remote interface available at http://localhost:7474/
可以看到配置文件位置:/etc/neo4j
,找到並去掉該句注釋#dbms.connectors.default_listen_address=0.0.0.0
,實現遠程訪問。
重新啟動,然后在瀏覽器輸入:http://server_ip:7474/
即可訪問。
驚不驚喜,激不激動!反正我心好累啊...因為我好迷茫...密碼又是啥啊!!!(默認密碼是neo4j)
在試了不加密碼和'neo4j'以后,又在網上找到了不需要密碼的方法,去掉#dbms.security.auth_enabled=false
的注釋,然鵝還是登!錄!不!進!去!
后來看瀏覽器控制台報錯,終於發現好像是ip:7687這個網址連接不上……好吧,又開了一個端口號,終於可以登錄了,凌晨一點多了,要哭了好嗎……說好的早睡呢……
打開之后是萬年不變的Hello World:
清空數據庫
文件存儲位置:/var/lib/neo4j/datadatabases/graph.db
直接全部刪除:rm -rf /var/lib/neo4j/datadatabases/graph.db
2. 基礎概念
Neo4j是一個NoSQL圖形數據庫。和SQL比,能更好的表現出數據之間的關系。Neo4j中記錄和關系有同等重要的地位。可以簡潔高效的查出節點之間的關系。
節點(Nodes):一個節點就是圖形數據庫的一條記錄。在圖中以一個圓圈的形式表現。
關系(Relationships):關系用來連接節點,一個關系連接兩個節點。關系是有向的,連接的點分為源點和目標點。不同的節點可以通過關系連接起來。(同一個節點也可以有關系,自環。)但是一個關系有且只能有一個類型(Types)。在圖中是連接圓圈的邊。
屬性(Properties):圖形數據庫中數據作為屬性存在節點中。屬性為鍵值對形式,一個節點可以有多個屬性。關系也可以擁有屬性。每一個節點或屬性都有一個integer類型的默認屬性id
,用來唯一標識節點/屬性。
標簽(Labels):用來標識一個節點屬於哪一類。一個節點可以有多個或0個標簽。標簽沒有屬性。(比如博客每一篇文章都有添加標簽選項,當寫一篇Java操作Neo4j的文章,可能會添加Java
和Neo4j
兩個標簽,當查看關於Java的文章時,可以通過標簽Java
快速搜索。也有點類似於接口,但是標簽沒有屬性,類似於沒有內容的接口>_<)
路徑(Path):看圖很好理解,就是從一個節點出發經過一些關系和節點之后,到達某個節點的全部過程。一個路徑看起來是(node)-[relation]-...-(node)
這樣子的。單獨一個節點也可以看做是一個長度為0的路徑。
可以通過``
(反單引號)將標簽或屬性名括起來防止和關鍵字沖突。
3. Cypher
Cypher是Neo4j的圖形查詢語言,關鍵字大小寫不敏感。(大寫打起來太麻煩了 一律用小寫...)語法和SQL很像,學起來相對簡單。
基本格式:
MATCH <pattern> WHERE <conditions> RETURN <expressions>
()
表示節點
[]
表示關系
{}
表示節點的屬性,每個屬性通過key:value的形式表示,多個屬性之間用逗號隔開
node:label1:label2
通過冒號給節點添加標簽,通過冒號分隔多個標簽
數據類型:
boolean
:true/false
integer
:64位整數
float
:64位浮點數
String
:Unicode字符串
[]
:表示數組
節點相關操作
-
節點
()
表示一個最簡單的節點,沒有標簽和屬性。
(:label1)
有一個標簽的節點
(:label1:label2:label3)
有多個標簽的節點
(:label1 {prop1:value1})
有一個屬性的節點
(:label1 {key1:value1,key2:value2})
有一個標簽和節點
(nodeName:label1 {key1:value1})
這里可以給node起一個別名,但是,這只是一個別名,和節點本身無關,是一個變量,用於后續語句操作該節點,而不是節點的名字。 -
新增
新增的關鍵字是CREATE
create (:女:成年:教師{age:28,name:'劉一'}); // 新增一個有三個標簽 兩個屬性的節點 create (N:男:成年:醫生{age:32,name:'陳二'}) return N; // 創建一個節點並返回
創建節點時將自動為節點生成一個
id
,id
是唯一且遞增的。 -
查找
查找的關鍵詞是MATCH
和WHERE
match可以用來匹配模式和簡單匹配數據,where用來限定條件。通過.
來引用節點的屬性Node.PropertyKey
,可以同時查詢多個節點並返回。match(n) return n; // 不設條件 查詢數據庫所有節點 match(n:男{age:32}) return n; // 匹配標簽有'男'且含有屬性age=32的節點 match(n) where n.age<30 return n; // 查詢屬性age<30的節點 match(n), where id(n)=1 return n; // 通過id查詢節點 match(n),(m:女) where id(n)=20 return n,m; // 同時查詢多個節點,當n,m都存在的時候才返回
-
修改
修改的關鍵字為SET
格式:
修改節點屬性:{{ 查詢語句 }} set n.propertKey=newValue;
添加節點標簽:{{ 查詢語句 }} set n:<label>
match(n{age:32}) set n.age=33; // 將所有age=32的節點的age屬性改為33 match(n) where id(n)=1 set n.age=33 return n; // 將所有age=32的節點的age屬性改為33 並返回修改后的節點 match(n) where id(n)=20 set n:神經病 return n; // 為節點添加一個標簽<神經病>
-
刪除
刪除關鍵詞:DELETE
,REMOVE
DELETE
:刪除節點,格式:DELETE <node>
REMOVE
:刪除節點或關系的標簽或屬性,格式:REMOVE node.propertyKey
,REMOVE node:label
match(n) where id(n)=23 delete n; // 刪除一個節點 match(n) where id(n)=20 remove n:`神經病` return n; // 刪除標簽 match(n) where id(n)=20 remove n.age return n; // 刪除屬性
當一個節點有關聯關系的時候,是不能被刪除的,必須要先刪除相關關系。
match (n) where id(n)=40 detach delete n; // 刪除一個節點相關關系 然后刪除該節點
關系相關操作
- 關系
--
無向關系
<--
、-->
有向關系
-[:type]->
表示一個類型為type的關系
-[:type {key1:value1,key2:value2}]
關系也可以有一個或多個屬性。
-[rel:type {key1:value1,key2:value2}]
同節點,這里rel只是關系的一個別名而已。
創建關系時必須有方向,關系也必須有且只有一個類型。
關系的操作和節點相仿。
-
新增
match (n{name:'劉一'}),(m{name:'陳二'}) create (m)-[r:love]->(n) return type(r); // 找到兩個節點並創建類型為`love`的關系,返回關系類型。 create (n1:N{name:'first'})-[r1:R]->(n2:N{name:'second'})<-[r2:R]-(n3:N{name:'third'}) return n1,r1,n2,r2,n3; // 創建了三個節點兩個關系
-
查找
單獨返回關系並沒有返回結果,可以選擇一起返回關系及關系相關節點,或者返回路徑。match ()-[r]-() where id(r)=13 return r; match (n)-[r]-(m) where n.name='劉一' and m.name='陳二' return n,r,m; // where中多個查詢條件用and連接 表示與關系 match p=(n)-[r]-(m) where n.name='劉一' and m.name='陳二' return p; // 查詢路徑
-
修改
match ()-[r]-() where id(r)=2 set r.reason=['fairness','cute','comely','gorgeous']; // 為關系新增了一個屬性`reason`,屬性值是一個數組。 match p=()-[r]-() where id(r)=2 set r.reason='no reason!' return p; // 又將`reason`屬性修改為字符串
-
刪除
remove 刪除屬性、delete 刪除關系match p=()-[r]-() where id(r)=2 remove r.reason return p; // 刪除關系屬性 match p=()-[r]-() where id(r)=2 delete r;
刪除所有節點&關系:
match (n) detach delete n;
Merge子句
Merge子句的作用有兩個:當模式(Pattern)存在時,匹配該模式;當模式不存在時,創建新的模式,功能是match子句和create的組合。在merge子句之后,可以顯式指定on creae和on match子句,用於修改綁定的節點或關系的屬性。
- 簡單匹配或創建
merge (n:狗{name:'dog'}) return n
將創建並返回節點'dog'
merge (n:狗{name:'dog'}) return n
返回已存在節點'dog' on create
如果是創建則執行
merge (n:狗{name:'dog1'}) on create set n.create=timestamp() return n
如果是新創建的節點就設置create
屬性,timestamp()
函數返回當前時間,類型為integer。on match
如果已存在則執行該子句
merge (n:狗{name:'dog'}) on match set n.update=timestamp() return n
- 可以同時指定
on create
和on match
merge (n:狗{name:'dogx'}) on create set n.version=0 on match set n.version=n.version+1 return n.version
查詢語句
清空數據庫,然后插入十條語句。並創建一些關系,用於后續查詢。
原諒我膚淺,只能想出這種數據……(捂臉)
MATCH (n) DETACH DELETE n
CREATE
(N1:女:成年:教師{age:28,name:'劉一',interest:['shopping','reading']}),
(N2:男:成年:醫生{age:28,name:'陳二',interest:['football']}),
(N3:女:未成年:學生{age:17,name:'張三',interest:['games']}),
(N4:男:成年:教師{age:23,name:'李四',interest:['reading']}),
(N5:女:成年:醫生{age:25,name:'王五',interest:['reading']}),
(N6:男:未成年:學生{age:13,name:'趙六'}),
(N7:女:成年:程序員{age:36,name:'孫七'}),
(N8:男:成年{age:68,name:'周八'}),
(N9:女:未成年:學生{age:16,name:'吳九'}),
(N10:男:未成年{age:15,name:'鄭十'}),
(N1)-[:love]->(N2)<-[:love]-(N3),
(N4)-[:know]->(N5),
(N4)-[:know]->(N6),
(N5)-[:know]->(N7),
(N5)-[:know]->(N8),
(N6)-[:know]->(N7),
(N7)-[:know]->(N8),
(N9)-[:hate]->(N8)
-
常用謂詞
and
表示查詢條件與關系,or
表示或關系,xnot
表示異或,not
表示非。
查詢年齡在[15,25]之間的女生:match (n:女) where n.age>=15 and n.age<=25 return n
查詢年齡不大於18的人:match (n) where not n.age>18 return n
-
其他常用關鍵詞
distinct
表示查詢去掉重復 有些查詢在圖形中表示不出來,需要到Table中查看查詢結果。
查詢所有人的年齡,並且去掉重復:match (n) return distinct n.age
order by
表示排序,默認升序。
查詢所有人按年齡排序:match (n) return n order by n.age desc
skip
表示忽略前面一定數量,limit
表示查詢數量。
查看年齡最大的五個人:match (n) return n order by n.age skip 5 limit 5
關鍵字in
表示是否包含在數組中。
查詢名字為'張三','李四','王五'的人:match (n) where n.name in ['張三','李四','王五'] return n
查詢喜歡閱讀的人:match (n) where 'reading' in n.interest return n
-
聚合函數
count()
,min()
,max()
,avg()
,sum()
,collect()
查詢年齡的平均值:match (n) return avg(n.age)
查詢學生數量:match (n:學生) return count(n)
查詢並返回所有人的集合:match (n) return collect(n)
-
常用函數
keys(node)
/keys(relationship)
查看節點或關系的屬性鍵。
查詢屬性:match (n)-[r]-() return keys(n), keys(r)
properties(node)
/properties(relationship)
查看的是屬性鍵值對。
查詢屬性值:match (n)-[r]-() return properties(n), properties(r)
exists()
查詢屬性是否存在
查詢存在interest屬性的節點:match (n) where exists(n.interest) return n
labels(node)
函數返回節點的標簽集合
查詢不是程序程序員的成年人:match (n) where '成年' in labels(n) and not '程序員' in labels(n) return n;
nodes(path)
查詢路徑相關節點,relationships(path)
查詢路徑相關關系。
返回路徑中的節點:match p=()-[:love]->()<-[:love]-() return nodes(p);
startNode()
,endNode()
查看關系的起止節點。
查看男女之間的關系(哪里奇怪?):match p=(:男)-[r]-(:女) return startNode(r).name, endNode(r).name;
-
查詢路徑
[*]
表示不限制路徑的長度。length(path)
查詢一條路徑長度。
查詢李四到周八的所有路徑:match p=({name:'李四'})-[*]-({name:'周八'}) return p, length(p)
[*n]
距離為n,[*..n]
最大距離為n,[*n..]
最小距離為n,[*m..n]
距離在m到n之間。
查詢李四到周八長度為2的路徑:match p=({name:'李四'})-[*2]-({name:'周八'}) return p
查詢最短路徑shortestPath
查詢李四到周八之間最短的路徑:match (n{name:'李四'}) match (m{name:'周八'}) return shortestPath((n)-[*]-(m)) as p
-
字符串匹配
starts with
,end with
,contains
查詢名字以'一'結束的節點:match (n) where n.name ends with '一' return n
正則表達式=~
也可以通過正則表達式查詢:match (n) where n.name =~ '.一' return n
-
WITH 子句
可以實現子查詢,隨便舉個例子,查詢版本姓名的xxx的年齡最大的人
match (n:people)
where n.name='xxx'
with max(n.age) as mage
match (m:people)
where m.name='xxx' and m.age = mage
return m;