Cypher是一种声明式图查询语言,表达高效查询和更新图数据库。Cypher是相对简单的查询语法,它让我们更关注业务领域问题。
Cypher语言的关键字不区分大小写,但是属性值,标签,关系类型和变量是区分大小写的。
Neo4j中不存在表的概念,只有标签(labels),节点(Node),关联(Relation),路径(path),标签里存的节点,节点和关系可以简单理解为图里面的点和边,路径是用节点和关系表示的如:(a)-[r]->(b),表示一条从节点a经关系r到节点b的路径。
在数据查询中,节点一般用小括号(),关联用中括号[]。
1:增加索引
2:优化neo4j配置文件
3:增加服务器内存
4:增加ssd固态硬盘
经查阅相关资料可知,neo4j数据库的索引一般分为三类。
① 手动索引:Neo4j数据库若采用手动方式创建索引,则索引并不会随着数据的改变而自动更新。虽然该种方法可以手动创建和维护索引,但由于较为麻烦,所以一般不采用。
② 自动索引:自动索引是一种通过修改配置文件来创建索引的方法,但是在目前的neo4j 3.x版本中已经摒弃了用该方法来创建索引,并建议使用模式索引代替之。
③ 模式索引:模式索引和关系数据库中的索引很相似, 每一个索引会对应一个标签和一组属性,无论是更新还是删除节点,索引都会自动更新或者删除,因此该种创建索引的方式更适用。
很显然采用模式索引会更简单方便,而建立模式索引,需要使用Cypher语句:CREATE INDEX ON: 标签(待查字段)。一般在浏览器http://172.18.34.25:7474/browser/网页上,可分别为待查字段建立模式索引。然而实验结果表明,建立索引后的查询时间虽有减少但不足以满足实际需求。另外有一点非常重要,索引建立后只是Populating状态,一定要一定要一定要重启数据库并关闭http://172.18.34.25:7474/browser/网页让索引ONLINE生效,否则刚刚建的索引是无效的,望大家切记。若不知道待查字段是否已有索引,可用“:schema”指令查看当前数据库中已建好的所有索引和索引是否ONLINE。
① 先明确neo4j的安装路径,然后执行“cd /home/public/Software/neo4j-community-3.3.7/conf/”指令进入指定目录下。由于要对neo4j配置文件进行修改,为了保险起见建议在对neo4j.conf文件进行修改之前,先备份一份neo4j.conf文件。
② 用“vim neo4j.conf”指令打开neo4j.conf文件并进行相应修改。经过查阅一些资料得知,通过添加jvm虚拟环境可以提高数据库的查询速度,即取消neo4j配置文件中关于dbms.memory.heap.initial_size=512m;dbms.memory.heap.max_size=512m两行的注释,并做合适的修改(最大堆内存越大越好,但是要小于机器的物理内存)。
由于“增加索引”和“优化neo4j配置文件”已经可以让neo4j数据库的查询时间得到了较大的缩减,并能满足一般的商业需求,所以暂时还未进行“增加服务器内存”和“增加ssd固态硬盘”的优化操作。
①:在测试前一定要为待查字段分别建立模式索引,建与不建的查询速度是非常显著的哈;
②:索引创建后一定要ONLINE才会生效,这点把我坑的好惨啊!
③:测试查询语句时,一定要尽可能将在一类标签中(其实相当于一张表)靠后或靠中间的节点属性作为查询条件,这样才能遍历更多的节点,故所得的测试结果才会真实可信;
④:增加WHERE语句、配合使用AND、OR等加大查询复杂度,另外还可以通过使用错误的范围语句来进行测试,如 “2020-10”<= P1.paper_publish_date <= “2017-10”;
⑤:测试语句也要将不存在的节点的属性作为查询条件,看返回空的时间如何;
⑥:学会优化Cypher查询语句,如
MATCH (a:Author)-[:author_is_in_field]->(f:Field)
WHERE f.field_level = “L3”
RETURN a.auhtor_name,f.field_name,f.field_reference_count
LIMIT 10
可以优化成
MATCH (a:Author)-[:author_is_in_field]->(f:Field{field_level:“L3”})
RETURN a.auhtor_name,f.field_name,f.field_reference_count
LIMIT 10
⑦:测试过程中,要想尽一切用户可能使用的场景来进行测试,切不可有意回避某些使用场景,否则不过是自欺欺人而已。
给大家推荐几个neo4j数据库学习网站:
【1】https://www.zhihu.com/question/45401120
【2】https://www.cnblogs.com/justcooooode/p/8182376.html
【3】https://blog.csdn.net/qq_37242224/article/details/81325625
【4】https://www.cnblogs.com/qianguyihao/category/587723.html
【5】https://www.cnblogs.com/loveis715/p/5277051.html
【6】https://blog.csdn.net/u011697278/article/details/52462420
【7】https://www.w3cschool.cn/neo4j/neo4j_need_for_graph_databses.html
【8】https://blog.csdn.net/u013946356/article/details/81739079
CREATE语句用于创建图元素:节点和关系、索引。
# 创建节点
CREATE (n)#创建单个节点
CREATE (n),(m)#创建多个节点
CREATE (p:Person)#创建带有标签的节点
CREATE (p:Person { name: 'Andres', title: 'Developer' })#创建同时带有标签和属性的节点
# 创建关系
MATCH (a:Person),(b:Person)
WHERE a.name = 'NodeA' AND b.name = 'NodeB'
CREATE (a)-[r:RELTYPE]->(b)
RETURN r #创建两个节点之间的关系:关系必须有箭头指向
MATCH (a:Person),(b:Person)
WHERE a.name = 'NodeA' AND b.name = 'NodeB'
CREATE (a)-[r:RELTYPE{ name: 'abc' }]->(b)
RETURN r#创建关系并设置属性
CREATE p =(andres { name:'Andres' })-[:WORKS_AT]->(neo)<-[:WORKS_AT]-(michael { name: 'Michael' })
RETURN p#创建一个完整路径:当使用CREATE和模式时,模式中所有还不存在的部分都会被创建
#创建索引
CREATE INDEX ON :Person(name)
关键字MERGE可以确保图数据库中存在某个特定的模式(pattern)。如果该模式不存在,那就创建它。
创建节点
//合并带标签的节点:如果没有包含Ctritic标签的节点,就会创建一个新节点。
MERGE (robert:Critic)
RETURN robert, labels(robert)
//合并带多个属性的单个节点
MERGE (charlie { name: 'Charlie Sheen', age: 10 })
RETURN charlie
//合并同时指定标签和属性的节点
MERGE (michael:Person { name: 'Michael Douglas' bornIn:'newyork'})
RETURN michael.name, michael.bornIn
//合并属性来自已存在节点的单个节点
MATCH (person:Person{ bornIn:'newyork'})
MERGE (city:City { name: person.bornIn })
RETURN person.name, person.bornIn, city
MERGE与CREATE搭配
//MERGE与CREATE搭配:检查节点是否存在,如果不存在则创建它并设置属性
MERGE (keanu:Person { name: 'Keanu Reeves' })
ON CREATE SET keanu.created = timestamp()
RETURN keanu.name, keanu.created
//MERGE与MATCH搭配:匹配节点,并在找到的节点上设置属性。
MERGE (person:Person { name: 'Keanu Reeves2' })
ON MATCH SET person.found = TRUE
RETURN person.name, person.found
//MERGE与CREATE和MATCH同时使用:检查节点是否存在,如果不存在则创建它并设置created属性,如果存在就修改lastSeen属性。
MERGE (keanu:Person { name: 'Keanu Reeves' })
ON CREATE SET keanu.created = timestamp()
ON MATCH SET keanu.lastSeen = timestamp()
RETURN keanu.name, keanu.created, keanu.lastSeen
MERGE关系
//匹配或者创建关系:使用MERGE去匹配或者创建关系时,必须至少指定一个绑定的节点。
MATCH (p:Person { name: 'Charlie Sheen' }),(m:Movie { title: 'The Matrix' })
MERGE (p)-[r:ACTED_IN]->(m)
RETURN p.name, type(r), m.title
//合并多个关系:当MERGE应用于整个模式时,要么全部匹配上,要么全部新创建。
MATCH (oliver:Person { name: 'Lilly Wachowski' }),(reiner:Person { name: 'Rob Reiner' })
MERGE (oliver)-[:DIRECTED]->(movie:Movie)<-[:ACTED_IN]-(reiner)
RETURN movie
//合并无方向关系:MERGE也可以用于合并无方向的关系。当需要创建一个关系的时候,它将选择一个任意的方向。
MATCH (p1:Person { name: 'Charlie Sheen' }),(p2:Person { name: 'Lilly Wachowski' })
MERGE (p1)-[r:KNOWS]-(p2)
RETURN r
//合并已存在两节点之间的关系:MERGE可用于连接前面的MATCH和MERGE语句。
MATCH (person:Person { name: 'riky' })
MERGE (city:City { name: person.bornIn })
MERGE (person)-[r:BORN_IN]->(city)
RETURN person.name, person.bornIn, city
//同时合并\创建一个新节点和关系
MATCH (person:Person{name: 'Demi Moore'})
MERGE (person)-[r:HAS_CHAUFFEUR]->(chauffeur:Chauffeur { name: person.name })
RETURN person.name, person.chauffeurName, chauffeur
MERGE的唯一性约束
当使用的模式涉及唯一性约束时,Cypher可以通过MERGE来防止获取相冲突的结果。
CREATE CONSTRAINT ON (p:Person) ASSERT p.name IS UNIQUE;
//如果节点未找到,使用唯一性约束创建该节点
MERGE (laurence:Person { name: 'Laurence Fishburne' })
RETURN laurence.name
//唯一性约束与部分匹配:当只有部分匹配时,使用唯一性约束合并将失败。
CREATE CONSTRAINT ON (n:Person) ASSERT n.role IS UNIQUE;
CREATE (alisanda:Person { name: 'alisanda', role: 'Gordon Gekko' })
MERGE (michael:Person { name: 'Michael Douglas', role: 'Gordon Gekko' })
RETURN michael
//错误消息:Node(1578733) already exists with label `Person` and property `role` = 'Gordon Gekko'
CREATE UNIQUE
CREATE UNIQUE语句相当于MATCH和CREATE的混合体—尽可能地匹配,然后创建未匹配到的。
可能会想到用MERGE来代替CREATE UNIQUE,然而MERGE并不能很强地保证关系的唯一性。
创建唯一节点
//创建未匹配到的节点:root节点没有任何LOVES关系。因此,创建了一个节点及其与root节点的LOVES关系。注意这里可以不指定关系方向
MATCH (root { name: 'root' })
CREATE UNIQUE (root)-[:LOVES]-(someone)
RETURN someone
//用含值的模式创建节点:没有与root节点相连的name为D的节点,所以创建一个新的节点来匹配该模式。
MATCH (root { name: 'A' })
CREATE UNIQUE (root)-[:X]-(leaf { name: 'D' })
RETURN leaf
//创建未匹配到带标签的节点
MATCH (a { name: 'Node A' })
CREATE UNIQUE (a)-[:KNOWS]-(c:blue)
RETURN c
创建唯一关系
//创建未匹配到的关系:匹配一个左节点和两个右节点之间的关系。其中一个关系已存在,因此能匹配到。然后创建了不存在的关系。
MATCH (lft { name: 'A' }),(rgt)
WHERE rgt.name IN ['B', 'C']
CREATE UNIQUE (lft)-[r:KNOWS]->(rgt)
RETURN lft, rgt
//用含值的模式创建关系
MATCH (root { name: 'root' })
CREATE UNIQUE (root)-[r:X { since: 'forever' }]-()
RETURN r
//描述复杂模式
MATCH (root { name: 'root' })
CREATE UNIQUE (root)-[:FOO]->(x),(root)-[:BAR]->(x)
RETURN x
SET语句用于更新节点的标签以及节点和关系的属性。
//设置属性
MATCH (n { name: ' Taylor Hackford' })
SET n.surname = 'Taylor'
RETURN n
//删除属性
MATCH (n { name: 'Taylor Hackford' })
SET n.surname = NULL
RETURN n
//在节点和关系间拷贝属性
MATCH (at { name: 'Andres' }),(pn { name: 'Peter' })
SET at = pn
RETURN at, pn
//从map中添加属性:当用map来设置属性时,可以使用+=形式的SET来只添加属性,而不删除图元素中已存在的属性。
MATCH (peter { name: 'Peter' })
SET peter += { hungry: TRUE , position: 'Entrepreneur' }
//使用一个SET语句设置多个属性
MATCH (n { name: 'Andres' })
SET n.position = 'Developer', n.surname = 'Taylor'
//设置节点的标签
MATCH (n { name: 'Stefan' })
SET n :German
RETURN n
//给一个节点设置多个标签
MATCH (n { name: 'Emil' })
SET n :Swedish:Bossman
RETURN n
delete 语句用于删除图元素(节点、关系、或路径)。 不能只删除节点而不删除与之相连的关系,要么使用 detach delete。
删除单个节点
match (n:Car) delete n
删除所有的节点和关系
这个查询适用于删除少量的数据,不适用于删除巨量的数据
match (n) detach delete n
删除一个节点及其所有的关系
match (n:{age: “34”}) detach delete n
remove 语句用于删除图元素的属性和标签。
删除一个属性
neo4j不允许属性存储空值null。如果属性的值不存在,那么节点或者关系中的属性将被删除。这也可以通过remove来删除。
match (andres {name: “huzong”}) remove andres.age return andres
删除节点的一个标签
match (n {name “huzong”}) remove n:Chinese return n
删除节点的多个标签
match (n {name “huzong”}) remove n:Chinese:Man return n
创建索引
create index on:Student(name)
删除索引
drop index on:Student(name)
创建唯一索引
create constraint on (s:Teacher) assert s.name is unique
删除唯一索引
drop constraint on (s:Teacher) assert s.name is unique
用于更新列表中的数据,或者来自路径的组件,或者来自聚合的结果
foreach 括号中的变量是与外部分开的,变量不能用于语句之外
foreach 括号里可以执行任何更新命令,create / create unique / delete / foreach
// 将设置路径上所有的节点的 flag 属性为 true
match p = (begin) -[*]-> (end) where begin.name=‘a’ and end.name = ‘z’
foreach (n in nodes§ | set n.flag = true )
// 将列表中的人全部加为 朋友
match (a:User) where a.userId = 1
foreach ( name in [‘a’,‘b’,‘c’] | create (a) --> (:User{name:name}) )
# 多个关系
MATCH (tom { name: 'Tom Hanks' })-[:ACTED_IN|ACTED_OF]->(movie)<-[:DIRECTED]-(director)
RETURN tom,movie, director
#可变长关系
#可变长关系和节点的语法如下:
#-[:TYPE*minHops..maxHops]->
#minHops和maxHops都是可选的,默认值分别为1和无穷大。当没有边界值的时候,点也可以省略。当只设置了一个边界的时候,如果点省略了就意味着是一个固定长度的模式。
#返回与' Tom Hanks '关系为1跳(hop)到3跳的所有电影。
MATCH (martin { name: 'Tom Hanks' })-[:ACTED_IN*1..3]-(movie:Movie)
RETURN movie.title
##查询路径
MATCH p =(tom { name: 'Tom Hanks' })-->()
RETURN p
#单条最短路径
#通过使用shortestPath函数很容易找到两个节点之间的最短路径。
#找到两个节点之间的最短路径,路径最大长度为15:
MATCH p =shortestPath((tom { name: 'Tom Hanks' })-[*..15]-( Steve {name:'Steve Zahn'}))
RETURN p
# 查询多个节点IN
MATCH (n)
WHERE id(n) IN [0, 3, 5]
RETURN n
OPTINAL MATCH语句用于搜索模式中描述的匹配项,对于找不到的项用null代替。
# 如果可选的元素为null,那么该元素的属性也返回null。
# 返回这个节点的外向关系。
MATCH (a:Movie { title: 'The Matrix' })
OPTIONAL MATCH (a)-->(x)
RETURN x, x.name
WHERE在MATCH或者OPTINAL MATCH语句中添加约束,或者与WITH一起使用来过滤结果。
(1)条件过滤
WHERE nineties.released > 1990 AND nineties.released < 2000
MATCH (n) WHERE n:Movie
WHERE exists(n.title)
(2)字符串匹配
STARTS WITH用于以大小写敏感的方式匹配字符串的开始。
ENDS WITH用于以大小写敏感的方式匹配字符串的结尾
CONTAINS用于检查字符串中是否包含某个字符串,它是大小写敏感的,且不关心匹配部分在字符串中的位置。
使用NOT关键词可以返回不满足给定字符串匹配要求的结果。
(3)正则表达式
可以使用=~ 'regexp’来进行正则表达式模糊匹配。
在正则表达式前面加入(?i)之后,整个正则表达式将变成非大小写敏感。
WHERE n.name =~ ‘(?i)TOM.*’
(4)其他关键字
WHERE type®=~ ‘DIRE.*’ #获得关系的类型
IS NULL # 空值过滤
检查某个元素是否在指定的范围,可以使用不等运算符<,>=和>。
DISTINCT用于仅仅 获取结果集中所依赖列的唯一行。
如果想使用空格等特殊字符,可以用反引号将其括起来。如下所示: MATCH (
This isn’t a common variable`)
如果希望列名不同于表达式中使用的名字,可以使用AS对其重命名。
如果某个属性可能存在,也可能不存在。这时,依然可以正常地去查询,对于不存在的属性,Cypher返回null。
任何表达式都可以作为返回项。如字面值,断言,属性,函数和任何其他表达式。
通过遗留索引(legacy index)查找开始点。START语句应当仅用于访问遗留的索引。所有其他的情况,都应使用MATCH代替,从Cyper3.2开始START语句已经被废弃。
- 聚合函数
count 计算数量
sum 求和
avg 平均值
percentileDisc 计算给定百分位在组中的值,数值从0.0~1.0,采用四舍五入返回最接近百分位的值 return percentileDisc(n.age, 0.7)
percentileCont 计算给定百分位在组中的值,数值从0.0~1.0,采用线性插值,在两个值之间计算一个加权平均数 return percentileCont(n.age, 0.7)
stdev 无偏估计的标准偏差,分母是n-1
stdevp 标准偏差
max/min 最大/最小- collect
collect将所有值收集作为一个列表返回,忽略空值。- distinct
去重,可用于聚合函数中。
ORDER BY是紧跟RETURN或者WITH的子句,它指定了输出的结果应该如何排序。
Cypher将先根据第一个变量进行排序,对于相等的值,然后再检查 ORDER BY中的下一个属性值,依次类推
DESC[ENDING],Cypher将以逆序(即降序)对输出进行排序。
当结果集中包含null值时,对于升序排列,null总是在结果集的末尾。而对于降序排序,null值总是排在最前面。
多个条件
ORDER BY r2.pinyinindex ASC, a.frequence DESC
限制输出的行数。
从哪行开始返回结果。
Skip接受任意结果为正整数的值,只要它不引用其他外部变量。
SKIP toInt(3*rand())+ 1
WITH语句将分段的查询部分连接在一起,查询结果从一部分以管道形式传递给另外一部分作为开始点。
使用WITH可以在将结果传递到后续查询之前对结果进行操作。操作可以是改变结果的形式或者数量。WITH的一个常见用法就是限制传递给其他MATCH语句的结果数。通过结合ORDER BY和LIMIT,可获取排在前面的X个结果。
unwind是cypher提供的一种列表遍历工具,类似于python中的for循环,unwind结合case等语法可以写出许多复杂的查询,尤其是对于路径查询的处理。foreach也是cypher提供的一个列表遍历工具,但是主要用来做增删改。对于这两个的用法,建议结合列表推导一起学习。
UNION可以组合两个或者两个以上的查询结果到一个结果中,需要注意一下几点:
(1)可以组合两个或者两个以上的查询结果。
(2)UNION和UNION ALL的用户不同,尤其需要注意UNION的用法。
(3)每个查询的结果列数和列名都必须相同。
这些函数官网原文叫predicate function,翻译过来就是谓词函数,对于为什么要这么叫我也觉得不是很能理解,在上世纪5 60年代,知识图谱前身的RDF,进行的推理中,就包含了本体推理和规则推理。规则推理中,最基础的就是所谓的一阶谓词逻辑,个人认为所谓的谓词大概就是简单的逻辑关系的判断吧。
all()、any()、exists()、none()、single()
这些预测函数都是bool类型,对于给定的非空输入返回true or false。它们最常用于过滤掉查询的where部分中的子图。
null值既不是true也不是false,所以Daniel节点也不会在返回结果
all():对所有元素都满足条件返回true,否则返回false。
any():在给定列表中有一个元素满足对应子句即可。
none():如果在给定的元素列表中没有元素满足对应条件,返回真值。
single() :如果在给定列表中,仅仅一个元素满足预测条件/筛选条件,则返回真。
length():对路径使用length()
id():返回某个节点或者关系的id,即下图中使用尖括号括起来的内置属性,在创建节点或者关系时会自动创建。
size():对字符串、列表和模式表达式使用size()
coalesce():返回表达式列表的第一个非空值
EndNode():返回关系中的结束节点 startNode()
Head():返回列表中的第一个元素。
Last():返回列表中的最后一个元素。
properties():以映射形式返回对应的属性
Type():返回关系的类型
timestamp():返回毫秒级时间戳
toBoolean():将字符串类型转换为Bool类型
toFloat():将整型或者字符串转换为浮点类型。除非有特定的需求,个人不建议在存属性时使用这两个函数。因为一旦使用这两个函数入库,后续如果要进行属性判断,也要写成这种形式:match (n) where n.age =toInteger(25),这样一是复杂。而是属性多了之后记不住自己最初转换了什么类型
toInteger():将字符串或者浮点类型转换为整型
聚合函数采用一组值并计算它们的聚合值。示例是avg(),用于计算多个数值的平均值,或min(),用于查找一组值中的最小数值或字符串值。当我们在下面说聚合函数对一组值进行操作时,我们的意思是这些是将内部表达式(例如n.age)应用于同一聚合组中的所有记录的结果。
可以在所有匹配的子图上计算聚合,或者可以通过引入分组键来进一步划分聚合。这些是非聚合表达式,用于对进入聚合函数的值进行分组。
要使用聚合对结果集进行排序,聚合必须包含在要在ORDER BY中使用的RETURN中。
DISTINCT运算符与聚合一起使用。它用于在通过聚合函数运行它们之前使所有值唯一。
avg() - Numeric values
collect() 返回列表
count() count(*)返回计数
max()
min()
percentileCont() //这两个方法没太看懂,还是先记录一下吧
percentileDisc()
stDevP() 返回除n的标准差
keys() //keys返回一个列表,其中包含节点,关系或映射的所有属性名称的字符串表示形式。这对于json数据也可以直接使用
labels()
nodes()
range()与Python的range不同,是左闭右闭的
relationships() //返回路径中包含的所有关系的列表 [:KNOWS[0{},:MARRIED[4]{}] 这里的0和4代表了什么,暂时还不清楚
reverse() 返回逆序列表
tail() //返回去除掉第一个元素的列表
abs() ceil() floor() 绝对值、向上取整、向下取整
rand() 返回[0,1)的随机数
round() 四舍五入
sign() 将正数、负数和0映射为1、-1、0
e() 返回2.71828
exp() log() e的n次方 自然对数:以e为底的对数
log10() sqrt() 其余三角函数自行查询手册
left() RETURN left(‘hello’, 3)//自左边起的3个字符
lTrim() 去除掉字符串左边的空格
replace() RETURN replace(“hello”, “l”, “w”)//返回hewwo
reverse() 字符串逆序
right() 与left相对
rTrim() 去除掉字符串右边的空格
split() RETURN split(‘one,two’, ‘,’)
substring() RETURN substring(‘hello’, 1, 3), substring(‘hello’, 2)//ell llo
toLower()、toString()、toUpper()
trim() 删除字符串首尾的空格
创建索引
create index on:Student(name)
删除索引
drop index on:Student(name)
创建唯一索引
create constraint on (s:Teacher) assert s.name is unique
删除唯一索引
drop constraint on (s:Teacher) assert s.name is unique
创建复合索引
CREATE INDEX ON :Person(age, country)
参考:
https://blog.csdn.net/qq_35793394/article/details/107833467
https://www.jianshu.com/p/9c8708b8addc
https://blog.csdn.net/qq_37503890/article/details/101382876
https://blog.csdn.net/weixin_42348333/article/details/89816699