Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4056862
  • 博文数量: 272
  • 博客积分: 7846
  • 博客等级: 少将
  • 技术积分: 6476
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-25 16:27
文章分类

全部博文(272)

分类: NOSQL

2017-05-20 05:32:22

  Cypher,读作(赛佛儿)。名词意为:零,零的记号,或密码索引书;动词含义为计算或用密码书写。不过,更准确的引申要从街舞中借鉴,在街舞中,Cypher就是围圈跳舞,不分先后,没有对手,就是一次一次即兴的到中间去跳在社会网络分析(SNA)中,Neo4j的核心实现形式语言就是功能类似这种围圈舞蹈的Cypher。
  Cypher我理解是一种联系操作语言,之所以将其称为“联系”就是要使之和传统SQL数据库的“关系”相区分。操作对象即图数据库独有的节点(Nodes)、标签(Labels)、联系(Relationships)和属性(Properties)。解释一下,以便理解的更为深入:
  • Node:表征实体,如:人、公司、账户或其他类似的东西。
  • Label:标签不是一开始就有的,后续更新的版本加入了这个功能,极为好用。因为人脑的两种基本认知方式之一就是分类,而标签就是最佳的方法。标签用于标识Node的类别,一个节点可拥有一个或多个标签。标签有助于创建索引,加速检索。
  • Relationship:联系定义了两个Node之间的连接。联系还可以有自己的属性和方向。
  • Property:用于存储Node的相关信息,是Node的内涵定义。属性可以被Node和Relationship拥有,一如Node一样,Property也是一种广泛而基本的存在。
  为了更深入地理解Cypher的语法,需要提前说明一下Cypher查询的执行过程:
  1. 首先,进行语法解析、正确性检查、产生执行计划;
  2. 其次,定位至初始节点;
  3. 再次,选择和遍历联系;
  4. 最后,更改或返回值。
  后续语法的执行基本上都是这四个步骤的不断重复。

一、基本语法(CURD):
1. Create
  试着创建一个Node,这个节点是一个人--顾双双,是我心理咨询的一个来访者,性别女,年龄23。仿照基本格式先写一个:
  1. create (顾双双:患者{gender:"女",age:"23"})
  请注意在下图的结果中,标签是“患者”,节点当前显示的名字是第一个标签的内容“女”:
  当然了,这和我的本意并不相符,我是打算创建姓名为“顾双双”的患者,希望姓名可以在Node中心显示出来。所以,现在CREATE的格式是:create (?:标签名{属性名1:"属性1值",属性名2:"属性2值"}),所以现在主要的问题是弄清楚“?”代表什么,或者这个部分是否可以省略。
  弄清楚了:?代表的是创建的本实例,正规的一个格式是:
  1. create (n:患者{gender:"女",age:23})
  注意两点,第一是n,第二是23旁边没有括号了,也就意味着该值不是字符型而是数值型。n实际上是可有可无的,用于捕获create的结果,可以有也可以没有。故而,“n:患者”也可以写成“:患者”,结果是一样的。
 好了,另一个与Create齐名的语法也必须介绍了,这就是:merge,非常非常重要。Merge好似if-else语句,基本逻辑是先检测merge后面的条件,看看有没有匹配的返回值,如果有则执行on merge分支,如果没有则走on create。逻辑很简单,humane:看是否需要merge,找到的话就合并,没找到就新建。
  首先,merge条件部分可以单独执行,不过意义不大:
  还是用例子说明:
  1. merge (x:患者{gender:"男"})
  2. on match set x.name = "小明", x.birthday = 2007/06/02
  3. on create set x.created_time = timestamp()
  结果如图,虽然执行成功:
  但年龄还是有问题:
  到stackOverFlow上找了一下,都说需要手工将时间转成timestamp,因为Neo4j只有一个timestamp()函数而且还没有参数,很多人在抱怨这个问题,估计官方日后一定会增强这方面的功能。
 执行了如下语句后,激活了On create分支,因为数据库中目前并没有 性别是“P”的患者:
  1. merge (x:患者{gender:"P"})
  2. on match set x.name = "小明", x.birthday = "2007/06/02"
  3. on create set x.created_time = timestamp()
  结果如图:


2. Update
  更新的操作实际上是由set命令完成的,首先要定位到待修改的节点或联系,然后进行修改。举个例子:
  1. match (x:患者) where x.gender="男" set x.age=100 return x
  这个例子说明不仅可以使用set更改值,还可以更改值类型,比如从string改为integer。

3. Retrieve
  实际上,查询或检索这一操作是Cypher实际应用中使用次数最频繁的,类似SQL数据库中的SELECT。在Neo4j中,主要是由Match及其后续限定的Where从句构成。
 比如,通过如下语句新增一个节点,现在数据库中有一男一女两个节点:
  1. create (:患者{gender:"男",age:"23"})
  输入如下语句,返回标签为“患者”的所有节点(当前是两个):
  1. match(x:患者) return x
  输入如下语句,返回标签为“患者”并且性别为“女”的所有节点(当前是一个
  1. match (x:患者) where x.gender="女" return x
  Where从句的语法和SQL非常相似,比如is not null或者=,之间还可以使用and、or等逻辑运算符进行组合。并且,除了Create和Delete语句,其他所有语句都应该以return结尾,否则报错。
 还有一个就是Optional Match,其他都一样,差别在于没找到Match不返回任何结果,而Optional Match返回NULL,如下图的records”所示:
  在Match查找前,可以进行定位以加快检索速度和效率。一般而言,Cypher语句以Start开始,每一条查询语句可以有多个起始点(starting points),借助start可以制定Legacy index,虽然这个东东现在已经被schema取代了,但为了后向兼容还是保留了基本功能,如下例所示:
  1. start n = node:nodesIndx (Gender = "男") return n
  然而,实际应用中,还有一个重要的检索功能必须掌握,那就是所谓的“Aggregation”。这种聚合实质上是grouping,就是对结果进行统计操作,小到count、max、min,大到stdev、stdevp,更不用说distinct了。比如将之前的例子的返回值加一个count:
  1. match (x:患者) where x.gender="女" return count(x)
  结果是1,如下图所示:
  OK,another trick,使用distinct:
  1. match (x:患者) where x.age="23" return count(distinct x.gender)
  结果如下,返回2,但如果是x.age则只是1啦:
  查询部分先总结到这儿。

4. Delete
  删除任何东西都可以使用Delete,但将上述创建的所有内容一口气删除,不能使用:
  1. match (n)
  2. delete n
  而应该使用:
  1. match (n)
  2. detach delete n
  因为使用第一种方式,会报错:“Cannot delete node<34>, because it still has relationships.”。究其原因,在于高版本的Neo4j加强了数据保护,对于有联系的节点,需要先删除联系再删除节点。然而,使用detach便开启了弱保护机制。
  但是,还有个好用的东东叫remove,专门用来删除属性和标签,比delete安全一些。比如:
  1. match (x:患者{gender:"P"}) remove x.created_time return x
  结果如下图,created_time属性就被删除了:

5. 总结
  之前说Cypher的优化主要是读操作,原因就在于所有操作(Create、Set、Delete或Remove)第一步就是要执行match,而match就是读操作,对特定节点或联系的定位都依赖于读操作。所以,读操作在图数据库中使用的是如此广泛和普遍,以至于成为主要的优化对象一点也不为过。
 已经写成长文了,这篇就先到此为止吧。

五岳之巅
2017年5月21日(孟菲斯时间)
11:57
终稿于UM, FIT



阅读(21812) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~