1.1 Cypher概述
Cypher是什么
Cypher是一種聲明式圖數據庫查詢語言,它具有豐富的表現力,能高效地查詢和更新圖數據。
Cypher借鑒了SQL語言的結構——查詢可由各種各樣的語句組合。
Cypher索引、約束、統計
索引
創建索引
使用CREATE INDEX ON可以在擁有某個標簽的所有節點的某個屬性上創建索引。注意,索引是在后台創建,並不能立刻就生效。
CREATE INDEX ON :Person(name)
本例在擁有Person標簽的所有節點的name屬性上創建了索引。
刪除索引
使用DROP INDEX可以刪除擁有某個標簽的所有節點的某個屬性上的索引。
DROP INDEX ON :Person(name)
使用索引
通常不需要在查詢中指出使用哪個索引,Cypher自己會決定。例
MATCH (person:Person { name: 'Andres' })
RETURN person
在WHERE等式中使用索引
在WHERE語句中的對索引的屬性進行相等比較時,索引將自動被使用。
MATCH (person:Person)
WHERE person.name = 'Andres'
RETURN person
使用WHERE不等式中使用索引
在WHERE語句中的對索引的屬性進行不等(范圍)比較時,索引將自動被使用。
MATCH (person:Person)
WHERE person.name > 'B'
RETURN person
在 IN中使用索引
下面查詢中針對 person.name的IN斷言將使用Person(name)索引。
MATCH (person:Person)
WHERE person.name IN ['Andres', 'Mark']
RETURN person
在STARTS WITH中使用索引
下面的查詢語句在針對person.name的STARTS WITH斷言將使用Person(name)索引。
查詢
MATCH (person:Person)
WHERE person.name STARTS WITH 'And'
RETURN person
在檢查屬性存在性時使用索引
下面查詢中的has(p.name)斷言將使用Person(name)索引。
MATCH (p:Person)
WHERE exists(p.name)
RETURN p
2.約束
Neo4j通過使用約束來保證數據完整性。約束可應用於節點或者關系。可以創建節點屬性的唯一性約束,也可以創建節點和關系的屬性存在性約束。
可以使用屬性的存在性約束確保擁有特定標簽的所有節點或者擁有特定類型的所有關系的屬性是存在的。所有的試圖創建新的沒有該屬性的節點或關系,以及試圖刪除強制屬性的查詢都將失敗。注意:只有Neo4j企業版才具有屬性存在性約束這個高級功能。
可以對某個給定的標簽添加多個約束,也可以將唯一性約束和存在性約束同時添加到同一個屬性上。
在屬性上添加唯一性約束的時候,同時也會自動為該屬性添加一個索引。因此,不能單獨地添加這樣一個索引。
節點屬性的唯一性約束
使用IS UNIQUE語法創建約束,它能確保數據庫中擁有特定標簽和屬性值的節點是唯一的。
CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE
刪除唯一性約束
使用DROP CONSTRAINT可以刪除數據庫中的一個約束。
DROP CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE
創建遵從屬性唯一性約束的節點
創建一個數據庫中還不存在的isbn的Book節點。
CREATE (book:Book { isbn: '1449356265', title: 'Graph Databases' })
創建違背屬性唯一性約束的節點
創建一個數據庫中已經存在的isbn的節點。
查詢
CREATE (book:Book { isbn: '1449356265', title: 'Graph Databases' })
這種情況下,節點將創建失敗。
錯誤消息
Node 0 already exists with label Book and property "isbn"=[1449356265]
因為沖突的節點而創建屬性唯一性約束失敗
當數據庫中已經有兩個Book節點擁有相同的isbn號時,在Book節點的isbn屬性上創建屬性唯一性約束。
CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE
這種情況下約束將創建失敗,因為它與已有的數據沖突。可以選擇創建索引或者移除沖突的節點然后再重新創建約束。
節點屬性存在性約束
使用ASSERT exists(variable.propertyName)創建約束,可確保有指定標簽的所有節點都有一個特定的屬性。
CREATE CONSTRAINT ON (book:Book) ASSERT exists(book.isbn)
刪除節點屬性存在性約束
使用DROP CONSTRAINT可以從數據庫中移除一個約束。
DROP CONSTRAINT ON (book:Book) ASSERT exists(book.isbn)
創建遵從屬性存在性約束的節點
創建一個存在isbn屬性的Book節點。
CREATE (book:Book { isbn: '1449356265', title: 'Graph Databases' })
創建違背屬性存在性約束的節點
在:Book(isbn)有存在性約束的情況下,試圖創建一個沒有isbn屬性的Book節點。
CREATE (book:Book { title: 'Graph Databases' })
錯誤消息
Node 1 with label "Book" must have the property "isbn" due to a constraint
刪除有存在性約束的節點屬性
在:Book(isbn)有存在性約束的情況下,試圖從一個已存在的Book節點移除isbn屬性。
MATCH (book:Book { title: 'Graph Databases' })
REMOVE book.isbn
這種情況下,移除屬性將失敗。
錯誤消息
Node 0 with label "Book" must have the property "isbn" due to a constraint
因已存在的節點而創建節點屬性存在性約束失敗
當數據庫中存在Book節點沒有isbn屬性時,試圖在Book標簽節點的isbn屬性上創建屬性存在性約束。
CREATE CONSTRAINT ON (book:Book) ASSERT exists(book.isbn)
這種情況因為與已存在的數據沖突,因此約束創建失敗。可以選擇移除沖突的節點,然后再重新創建約束。
錯誤消息
Unable to create CONSTRAINT ON ( book:Book ) ASSERT exists(book.isbn):
Node(0) with label Book
has no value for property isbn
關系屬性存在性約束
使用ASSERT exists(variable.propertyName)創建約束,可確保特定類型的所有關系都有一個特定的屬性。
CREATE CONSTRAINT ON ()-[like:LIKED]-() ASSERT exists(like.day)
刪除關系屬性存在性約束
使用DROP CONSTRAINT從數據庫中移除一個約束。
DROP CONSTRAINT ON ()-[like:LIKED]-() ASSERT exists(like.day)
創建遵從屬性存在性約束的關系
創建一個存在day屬性的LIKED關系。
MATCH (TomH:Person {name:'Tom Hanks', born:1956}), (book:Book { isbn: '1449356265', title: 'Graph Databases' })
CREATE (TomH)-[like:LIKED { day: 'yesterday' }]->(book)
return TomH,book
創建違背屬性存在性約束的關系
在有:LIKED(day)存在性約束的情況下,試圖創建一個沒有day屬性的LIKED關系。
MATCH (Nora :Person {name:'Nora Ephron'}), (book:Book { isbn: '1449356265', title: 'Graph Databases' })
CREATE (Nora)-[like:LIKED]->(book)
return Nora,book
這種情況下,關系將創建是吧。
錯誤消息
Relationship 1 with type "LIKED" must have the property "day" due to a constraint
移除具有存在性約束的關系屬性
有:LIKED(day)存在性約束的情況下,試圖從一個已有LIKED關系中移除day屬性。
MATCH (TomH :Person {name:'Tom Hanks'})-[like:LIKED]-> (book:Book { isbn: '1449356265', title: 'Graph Databases' })
REMOVE like.day
錯誤消息
Relationship 0 with type "LIKED" must have the property "day" due to a constraint
因已存在的關系而創建關系屬性存在性約束失敗
當數據庫中存在LIKED關系沒有day屬性時,試圖在LIKED關系的day屬性上創建屬性存在性約束。
CREATE CONSTRAINT ON ()-[like:LIKED]-() ASSERT exists(like.day)
這種情況因為與已存在的數據沖突,因此約束創建失敗。可以選擇移除沖突的關系,然后再重新創建約束。
錯誤消息
Unable to create CONSTRAINT ON ()-[ liked:LIKED ]-() ASSERT exists(liked.day):
Relationship(0) with type LIKED
has no value for property day
3.統計
當執行一個Cypher查詢時,它將先編譯為一個執行計划(execution plan),該計划可以運行並響應查詢。為了給查詢提供一個高效的計划,Neo4j需要數據庫的信息,如schema有什么索引和約束存在?Neo4j也使用統計信息來保持數據庫優化執行計划。有了這些信息,Neo4j就能決定采用哪種模式將獲得最好的執行計划。
Neo4j通過對數據采樣來獲得如下統計信息:
擁有特定標簽的節點的數量
每個索引的可選擇性
按類型分的關系的數量
以擁有指定標簽的節點開始或者結束的關系,按類型分各自的數量
Neo4j以兩種方式來保持這些統計信息的更新。以標簽數量為例,每當設置或者刪除一個節點的標簽的時候,這些數量都會被更新。Neo4j需要掃描所有索引以獲得可選擇的數量。
配置選項
當上述統計信息發生變化時,緩存的執行計划將被重新生成。下面的配置項可以控制執行計划的更新。
dbms.index_sampling.background_enabled
控制當需要更新時索引是否會自動重新采樣。
dbms.index_sampling.update_percentage
控制多大比例的索引被更新后才觸發新的采樣
cypher.statistics_divergence_threshold
多少統計信息發生變化后當前的執行計划就被認為過時了(需要重新生成執行計划)。參數值0.0意味着有變化就更新,1.0意味着永遠都不更新。
手動索引采樣
重新采樣可使用內嵌的db.resampleIndex()和db.resampleOutdatedIndexes()兩個內嵌過程來觸發。
下面是觸發重采樣的例子:
CALL db.resampleIndex(":Person(name)");
CALL db.resampleOutdatedIndexes();
[]在Windows環境中安裝Neo4j(https://www.cnblogs.com/ljhdo/archive/2017/05/19/5521577.html)