Neo4j入门点滴(二):模式与模式匹配

简介:   Announcement: All data comes from the book "Building Web Applications with Python and Neo4j", just for study & not for commerce.  模式及模式匹配(Pattern and Pattern matching)此乃Cypher的核心,描述了我们想要查找、创建或更新的数据的形状。
  Announcement: All data comes from the book " Building Web Applications with Python and Neo4j ", just for study & not for commerce.

 模式及模式匹配(Pattern and Pattern matching )此乃Cypher的核心,描述了我们想要查找、创建或更新的数据的形状。不理解模式和模式匹配,就写不出既有效果又有效率的查询。

一、数据准备
 首先,输入如下命令清空当前数据库:
  1. match (n)-[r]-(n1) delete n,r,n1;
  2. match (n) delete n
  第一条命令删除相互联系的所有节点及其联系,第二句则删除所有独立的节点。
 然后,创建一堆男人和女人:
  1. CREATE (bradley:MALE:TEACHER {name:'Bradley', surname:'Green',age:24, country:'US'})
    CREATE (matthew:MALE:STUDENT {name:'Matthew', surname:'Cooper',age:36, country:'US'})
    CREATE (lisa:FEMALE {name:'Lisa', surname:'Adams', age:15,country:'Canada'})
    CREATE (john:MALE {name:'John', surname:'Goodman', age:24,country:'Mexico'})
    CREATE (annie:FEMALE {name:'Annie', surname:'Behr', age:25,country:'Canada'})
    CREATE (ripley:MALE {name:'Ripley', surname:'Aniston',country:'US'})
  此时有节点但没有联系,结果如下图:
 然后我一堆输入下列联系语句,总报错。但逐条输入就没问题了:
  1. MATCH (bradley:MALE{name:"Bradley"}),(matthew:MALE{name:"Matthew"})WITH bradley, matthew CREATE (bradley)-[:FRIEND]->(matthew) , (bradley)-[:TEACHES]->(matthew);
  2. MATCH (bradley:MALE{name:"Bradley"}),(matthew:MALE{name:"Matthew"})WITH bradley,matthew CREATE (matthew)-[:FRIEND]->(bradley);
  3. MATCH (bradley:MALE{name:"Bradley"}),(lisa:FEMALE{name:"Lisa"})WITH bradley,lisa CREATE (bradley)-[:FRIEND]->(lisa);
  4. MATCH (lisa:FEMALE{name:"Lisa"}),(john:MALE{name:"John"})WITH lisa,john CREATE (lisa)-[:FRIEND]->(john);
  5. MATCH (annie:FEMALE{name:"Annie"}),(ripley:MALE{name:"Ripley"})WITH annie,ripley CREATE (annie)-[:FRIEND]->(ripley);
  6. MATCH (ripley:MALE{name:"Ripley"}),(lisa:FEMALE{name:"Lisa"})WITH ripley,lisa CREATE (ripley)-[:FRIEND]->(lisa);
  现在可以看到基本数据集合的样貌:

、模式简介

(1)Pattern for Nodes
  匹配节点是最基本也是最简单的一种,使用括号进行描述。但是要注意,如果不额外使用属性或标签,那么括号可以省略:
  1. MATCH (a) return a
  2. 等价于:
  3. MATCH a return a;
  结果有四个节点都是男性,如图:

(2)Pattern for Labels

  就是增加“:标签”进行限定,需要说明的是,可以同时使用多标签,起到交集的作用,如下第二句就使用了多标签:
  1. MATCH (n:MALE) return n;
  2. MATCH (n:MALE:TEACHER) return n;
  结果返回的只有一个节点:

(3)Pattern for Relationships
  联系就是两个给定节点之间的连接,既可以是单向的,也可以是双向的,由[]和命名组成。
 看一个单向的例子:
  1. match (a:TEACHER)-[b:TEACHES]->(c:STUDENT) return a,b,c
  在这个例子中,系统首先搜寻TEACHER和STUDENT标签的节点,然后在这些节点中再找寻符合TEACHES联系的。
 双向就是不需要箭头标识了,如下:
  1. match (a:MALE)-[b:FRIEND]-(c:FEMALE) return a,b,c

(4)Pattern for property
  属性的匹配使用的是花括号和键值对,其间使用都好分隔,如下:
  1. match (a:MALE{ name:"John", age:24} return a

三、使用Where从句
(1)Where
  如果仅仅使用Pattern并不能充分地满足要求,别懵逼,还有Where在。可以使用Where进一步过滤数据,但是要注意Where条件句本身并不能单独使用,只能用在match、optionalmatch、start或with的后面。比如:
  1. match (x)
  2. where x.age
  3. return x
  此时,只有一个人符合要求:


(2)Where从句中使用Pattern
  对于一个集合而言,如果是空集,那么就代表false,非空则表示true。可以使用in这个关键词来进一步限定:
  1. match (x)
  2. where x.name in ["John", "Andrew"] and x.age is not NULL
  3. return x
  当然,也可以使用not和正则表达式进行过滤:
  1. match (x)
  2. where x.name =~ "J.*"
  3. return x
  在这种情况下,不是= ~"xxx",而是 =~ "xxx",也就是说=~这是一个符号,千万别写错了。
 好了,以下要介绍一些此书上没有 技巧
  [1] 使用别名:
  1. with 'AGE' as haha
  2. match (x)
  3. where x[toLower(haha)]
  4. return x
  注意,Neo4j中属性名是大小写敏感的,如果写成x.AGE,则系统会提示并没有该属性:

  但是,“.”并不等同于“[]”,比如如下写法就是错误的:

  Why?我终于发现,并非 “.”不等同于“[]”,而是二者确实相等,但用法有讲究。对于[]而言,其间必须是常量,所以当我把x[age]写成x['age']后,就顺利通过了,而且返回结果与x.age一样:


  [2] 使用 exists()函数进行属性检验
  1. match (x)
  2. where exists(x.age)
  3. return x.name
   以前使用过has(),但现在被exists()代替而移除了

  [3] 字符匹配:
 这绝对是一把利器,使用starts with、ends with或contains,匹配字符串以何种模式开始,以何种模式结束或者其中包含什么。非常便利!比如:
  1. match (x)
  2. where x.name starts with "B"
  3. return x.name
  或者:
  1. match (x)
  2. where x.name contains "a"
  3. return x.name

(3)其他从句
  [1] order来排序(默认是升序,支持混排)
  [2] limit来限定返回数,skip则表示忽略最前面的。从而使用limit和skip的组配,可以取到中间的值:
  1. match (x)
  2. return x
  3. order by x.age skip 3 limit 2
  返回的就是“不要前3个,只要第4和第5”。确实很灵活!

(4)with从句
  with也是非常有用的一种从句,在介绍with之前,需要先研究一下“,”。比如在如下语句中,逗号是作为并列出现的,结果返回x和y两个人的信息,包括return语句中的x,y之间的逗号也都是这种用法。
  1. match (x{name:"John"}),(y{name:'Annie'})
  2. return x,y
  好的,继续,对于如下的初始情况:

  执行以下的语句会有什么结果?
  1. match (x{name:'Lisa'})
  2. return count(y)
  我觉得应该是2,但我错了,结果是4。如下图:

  为什么会是这样?也就意味着把两个间接的联系也算上了?好吧,自己再试试,这次用双向试试。结果大跌眼镜,依旧是4:
  1. match (x{name:'Lisa'})--(y)--()
  2. return count(y)
  用Brandley的结果竟然是8,使用有方向的话是3。我又重新核对了一遍预设的所有联系,确实不应该是3。 难道是BUG?(需要换个版本试试
  OK,话说回来,让逗号出现在with中,书中的例子如下:
  1. match (x{name:'Bradley'})--(y)-->()
  2. with y, count(*) AS cnt
  3. where cnt > 1
  4. return y
  返回值是Matthew,这没问题。因为符合模式的所有记录中,只有Matthew超过两条联系。问题来了,必须写with y才能限定吗?如果我去掉y呢?
  1. match (x{name:'Bradley'})--(y)-->()
  2. with count(*) AS cnt
  3. where cnt > 1
  4. return cnt
  cnt的值就变成了3,好的,我再加上y,看看cnt值:
  1. match (x{name:'Bradley'})--(y)-->()
  2. with y, count(*) AS cnt
  3. where cnt > 1
  4. return cnt
  这时,返回的cnt就成了2了。上述的尝试充分说明了with y, xxx这个模式中,逗号前的y起 到限定的作用,如果不加y,那么:
  1. match (x{name:'Bradley'})--(y)-->()
  2. return count(*)
  记录数就是3,表示命中的自Bradley发出的3条联系及其节点,如果推论正确,那么添加一个z表示目标节点,那么count(z)就应该是2个:
  1. match (x{name:'Bradley'})--(y)-->(z)
  2. return count(z)
  结果是3个,但是如果我加上distinct,则变成了2个:
  1. match (x{name:'Bradley'})--(y)-->(z)
  2. return count(distinct z)
  明白了,有些东东重复计算了,现在再试一下那些不解的例子:




  也就是说,有向联系的结果加入distinct是正确的,没有问题,不加就是4和2。无向联系就见了鬼了:

  更加奇怪的是,一下结果并不返回John:

  天啊,神啊。我终于发现是怎么回事了,都是我的错!怪我并没有理解的很深。
 细细讲一下,我一直把(x)--(y)--()当成了一组联系,实际上这是错误的,因为联系并不是用()表示,而是用[]表示。看看,不论有方向还是没有方向,这下全对了:


  好吧,现在主要来看()--()--()三个括号的连用。那么我先试试-而不是--,如:

  很显然,结果是错误的。也就是说match (x{name:'Lisa'})-(y)-(z),这种写法就是不对的。当然,换成--就没有语法错误了:match (x{name:'Lisa'})--(y)--(z) return count(*),但结果是4。现在我明白,因为(a)--(b)--(c)表示节点之间的连接关系,就是说要满足a是Lisa,而且b和a是连接的,并且c还要和b相连。通俗地讲,就是以a为中心,向外扩2层。如果我理解的是对的,那么 match (x{name:'Lisa'})--(y)--(z) return z,结果就应该是最外层的两个节点了。而且match (x{name:'Lisa'})--(y) return count(*),就应该与Lisa直接相连的3个节点罗。试试,检验一下:

  恭喜自己,虽然费了番周折,但终于搞定!反过来说,对于联系也可以这么玩:[a]-(b)-[c],我没试,但我相信是可以的。Cypher真的很灵活!
 接来下,使用with x增加限定条件,进行创建。但我发现不论有没有这个with x,都是一样的,创建了三个kai:



(5)union和union all从句
  union的用法与SQL一样,用于连接两个Match,返回结果中剔除了重复记录。但union all功能一样,但不剔除重复记录。
  1. match (x:MALE)-[:FRIEND]->() return x.name, labels(x)
  2. union
  3. match (x:FEMALE)-[:FRIEND]->() return x.name, labels(x)
  labels()返回的是全部的标签,有几个返回几个,如下图所示:

  但是,要注意:没有label()这个返回一个标签的函数。

 这一篇博文更长,终于告一段落了。接下来会开启第三篇。

                                               五岳之巅
                                   2017年5月23日(孟菲斯时间)
                                                  20:37
                                             终稿于Dorsey

相关文章
|
6月前
|
SQL 关系型数据库 MySQL
MySQL数据库基础第一篇(SQL通用语法与分类)
MySQL数据库基础第一篇(SQL通用语法与分类)
|
4月前
|
算法 测试技术 Python
Python接口自动化测试框架(基础篇)-- 有点意思的运算符
这篇文章介绍了Python中的各种运算符,包括算术运算符、比较运算符、赋值运算符、逻辑运算符、成员运算符、位运算符和身份运算符,并讨论了运算符的优先级,以及序列类型的相关知识。
25 0
Python接口自动化测试框架(基础篇)-- 有点意思的运算符
|
6月前
|
Java Maven Docker
几种常见的构建模式及其使用方法
几种常见的构建模式及其使用方法
75 3
|
SQL 数据管理 数据库
关系数据库SQL语言简介
关系数据库SQL语言简介 一、SQL语言概述 SQL(Structured Query Language)是一种用于管理和操作关系数据库的语言。它是数据库管理系统(DBMS)的核心组成部分,用于定义、操作和查询数据库中的数据。SQL语言是一种标准化的语言,由美国国家标准局(ANSI)和国际标准化组织(ISO)制定和维护。 SQL语言具有简洁、易学、易用的特点,被广泛应用于各个领域的数据管理和应用开发中。通过SQL语言,用户可以使用简单的语句来完成复杂的数据查询、更新、删除等操作,实现对数据库的全面管理和控制。 SQL语言主要包括以下几个方面的内容: 1. 数据定义语言(DDL):用于
127 0
|
7月前
|
Python
正则表达式高级用法
正则表达式是强大的文本匹配工具,常用于搜索、匹配和验证字符串。高级用法包括:捕获组(区分需要提取的内容)、非捕获组(减少开销)、零宽断言(定位匹配位置)、反向引用(匹配相同内容)、嵌入代码(实现复杂逻辑)、贪婪与非贪婪匹配(控制匹配范围)和递归匹配(处理嵌套结构)。了解这些高级技巧能提升字符串操作效率。示例展示了验证Email、电话号码、提取URL和清理多余空格的正则表达式应用。
|
6月前
|
数据处理 Python
掌握 Python 条件控制:从基础语法到高级应用
掌握 Python 条件控制:从基础语法到高级应用
|
7月前
|
Python
【Python指南 | 第八篇】自定义函数、输入输出,这一篇就够了
【Python指南 | 第八篇】自定义函数、输入输出,这一篇就够了
167 0
|
Linux Shell Perl
Linux环境下的字符串处理:基础到高级
在Linux系统中,字符串处理是一个非常常见的任务,无论是在系统管理、文本处理还是脚本编程中。本文将从基础的字符串操作开始,逐步深入,介绍Linux下的字符串处理技术,包括基础的命令行操作、常见的文本处理工具、Shell脚本中的字符串操作等。
273 1
|
缓存 API C++
|
机器学习/深度学习 SQL 数据库
NEO4J的入门和一些简单的操作
> 持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第29天,[点击查看活动详情](https://juejin.cn/post/7147654075599978532 "https://juejin.cn/post/7147654075599978532") # 引言 今天我们继续学习NEO4J. # 创建 创建语句我们一般会使用create指令 我们首先在控制台上输入`neo4j.bat console`启动neo4j 然后打开你的浏览器,然后在浏览器地址栏中输入 `http://localhost:7687 - Neo4j Browser](http: