暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Neo4j之Cypher语言基础

DCEGJ 2021-05-09
2468


TOC:一、概述二、基本语法结构三、关键字及语法四、函数五、性能调优

一、概述

Cypher也称为CQL是一种声明式图数据库查询语言。和SQL一样声明式语言只专注于图的表达而不关注怎么获得结果Cypher持事务,要么全部成果,要么全部失败。可以将多个查询放到一个事务中去提交。同时Cypher也支持唯一性,但只包括节点的唯一性,即查找“自己朋友的朋友”时,不会再查到自己;查询关系时,Cypher将尝试匹配两个方向的关系,互换开始结束节点,故系并没有唯一性。

二、基本语法结构

Cypher语言主要分为增删改查(CRUD)四个部分,也可抽象成读和写两个部分。但是不能同时读和写数据,每个部分要么匹配,要么更新。当需要使用聚合进行过滤时,必须使用WITH将读和写连接起来。

基本语法:

  • 单行注释使用//

  • 关键字大小写不敏感,变量名大小写敏感

  • null意味着“一个未找到的未知值”,对待null的方式会稍有不同,具体含null值的计算需要查表

  • 出现特殊字符用反引号  ` 括起来

  • 字符串连接用+

  • 返回所有结果使用星号RETURN *

基本概念

1. 点

节点有若干个标签,若干个属性,属性用键值对表示。

  • 节点用圆括号()
    表示

  • 标签用冒号:
    表示,节点可以有多个标签

  • 节点属性用花括号加键值对{键值对}
    表示

示例:点

    ()        //匿名节点
    (matrix)   //命名节点
    (:Movie)   //标签
    (matrix:Movie)   //命名节点+标签
    (matrix:Movie:Film)   //多标签
    (TheMatrix:Movie {
    title:'The Matrix'released:1999
    tagline:'Welcome to the Real World'}) //节点标签+属性


    2. 边

    总有开始节点和结束节点,有且只有一个方向,有且只一个类型,可以有若干属性,属性用键值对表示。

    • 边用中括号[]
      表示

    • 类型用冒号:
      表示,只能有一个,可用|
      做多选一

    • 边的属性用花括号加键值对{键值对}
      表示

    • 使用*
      指定关系的长度,使用..
      指定可变长度

    示例:边

      (点1)-[:关系标签 {p1:['属性1']} ]->(点2)
      ()-[r]-()                  //关系命名为r            
      ()-[:关系]-()    //关系唯一,命名省略
      ()-[:关系1|关系2|关系3]-()  //关系多选一         
      (a)-[*2]->(b)     //关系的长度为2,即边的数量为2,即(a)-[r1]->(c)-[r2]->(b),注意边的方向
      (a)-[*3..5]->(b)    //关系的长度为3~5,即满足3种模式
      p=(a)-[*2]->(b)     //命名路径

      注:当两点之间的关系是变长的,返回他们之间的关系可能就是一个关系列表!

      注:如果变成路径的下界为0,则意味着两个节点为同一个节点。


      • 图数据库与关系型数据库的类比

      图数据库关系型数据库
      点标签表名
      点属性表字段
      点数据(标签+属性键值对)表的一行数据
      相同标签的点数据表的所有数据

      类比示例:

      元素图数据库关系型数据库
      (matrix)entity
      点标签(matrix:Movie)create table Movie (...)
      点属性{title,release,tagline}create table Movie (id uuid pirmary key, title char,release number,tagline text);
      点数据(标签+属性键值对)(TheMatrix:Movie {title:'The Matrix', released:1999, tagline:'Welcome to the Real World'})select * from Movie where id = 0;
      相同标签的点的所有数据MATCH (n:Movie) RETURN n LIMIT 25;select * from Movie limit 25;

      相同标签一般拥有相似属性,不完全一样 <> 表的一行数据的列式相同的

      示例:查询相同标签的所有点

      3. 模式(Patterns)

      点和边中单个元素信息比较局限,而图数据库的查询主要依赖于模式。最简单的(点)-[边]-(点)
      可以组成一个最简单的模式。图数据库中,复杂的模式可以表达任意复杂的概念。使用模式可以描述为你期望看到的图的形状

      示例:

        create (Lily:Person{name:'Lily'})-[r:friend]->(Tom:Person{name:'Tom'})
        create (A:Person{name:'A'})-[r1:friend]->(B:Person{name:'B'})-[r2:friend]->(C:Person{name:'C'}) //朋友的朋友

        create (:Person)-[:LIVE_IN]->(:City)->[:PART_OF]->(:Country) //人-》城市-》国家
        Lily,Tom,A,B,C --> 点
        r,r1,r2 --> 边
        Lily 和 Tom 为朋友 --> 关系,简单模式
        C为A朋友的朋友 --> 复杂模式

        Neo4j保证单个模式中匹配结果的唯一性,即查找“朋友的朋友”时,不会再查到自己。

        数据类型

        • 数值型

        • 字符串:'Hello Cypher' "Hello Cypher"

        • 布尔型:true, false, TRUE, FALSE

        • 节点

        • 关系

        • 路径

        • 映射(Map)

        • 列表(List):['a','b'], [1,2,3], ['a','2','$param], []

        下面对一些特殊数据类型进行说明:

        数据类型之列表(List)

        使用[ , , ]
        来创建一组元素的列表。Cypher对于List的支持很好,常用使用方法如下:

        • range() 创建一个序列,左闭右闭

          RETURN range(0,10) as list1 
          结果:[0,1,2,3,4,5,6,7,8,9,10]
        • 使用[]访问list中的元素

           with range(1,5) as list
           with list,   //"[1,2,3,4,5]"
           list[0] as c1,  //1
           list[3] as c2,   //第4个元素,从0开始
           list[-3] as c3,  //倒数第3个元素
           list[1..3] as c4 //第2~第3个元素,左闭右开
           return list,c1,c2,c3,c4;
           结果:"[1,2,3,4,5]",1,4,3,"[2,3]"
        • 如果list值越界了返回null

        • size() 获取列表长度

           with range(0,5) as l
           return l,size(l) as s;
           结果:"[1,2,3,4,5]",6
        • List推导式(Comprehension)

          通过映射和过滤函数,用已经存在的list构建新的list。整个断言包括WHERE都可被省略。 示例:例如10以内的整数 --> 10以内的偶数的立方

           return [x in range(0,10) where x % 2 = 0 | x^3 ]
           结果:"[0.0,8.0,64.0,216.0,512.0,1000.0]"
           
           //模式推导式,注意区别        
           MATCH (a:Person {name: 'Keanu Reeves'})
           RETURN [(a)-->(b) WHERE b:Movie | b.released] AS years

        转义字符

        字符含义
        \t制表符
        \b退格
        \n换行
        \r回车
        \f换页
        \'单引号
        \"双引号
        \\反斜杠

        变量

        可以对点、边、模式等用变量命名,在后面的语句中引用他们。类似SQL中的别名。变量区分大小写。包含字母数字下划线。如果有特殊字符可用反引号`括起来。变量只在同一个查询内可见。

        参数

        可以使用参数代替字面量来写Cypher。参数为字母+数字。已json文件的格式提供,具体如何提交取决于使用的驱动程序。

        示例:参数

         {  "name": "John" }

        示例:使用参数构建查询

         MATCH (n)
         WHERE n.name = $name
         RETURN n;
         
         MATCH (n {name: $name}) RETURN n;

        运算

        • 比较等于和不等于使用= 和 <>

          • 相同类型只有

          • 不同类型不能比较,例如点和边和路径不能互相比较

          • List比较时,只有所有对应元素都相等列表才相等

          • Map比较时,只有Map的键相等且其指向的值也相等时才相等

          • 路径比较时,只有路径上所有的点和边都相等时才相等

        • 和null比较的结果还是null

        三、关键字及语法

        Cypher语法总体分为读和写,常用关键字如下:

        • 读:MATCH, OPTIONAL MATCH, WHERE, START, 聚合, LOAD CSV

        • 写:CREATE, MERGE, SET, DELETE, REMOVE, FOREACH, CREATE, UNIQUE

        • 通用: RETURN, ORDER BY , LIMIT , SKIP, WITH, UNWIND, UNION , CALL

        MATCH

        常与where联用、可以出现在查询的开始或结尾,可以出现在with之后。

         //查询
         match (n) return n;
         match (n:Movie) return n.title;
         match (person {name:'Keanu Reeves'})--(movie) return distinct movie.title;
         match (n {title: 'the matrix'}) return n;
         match (:Person {name:'Keanu Reeves'})-[r]-(movie) return distinct movie.title,type(r);
                                                                                         
         //关系多选一                                                                            
         match (person:Person )-[r:ACTED_IN | DIRECTED]-(movie) return person,movie;

        OPTIONAL MATCH

        相当于SQL中的OUTER JOIN,找的和MATCH一样,找不到的项用null代替。

        WHERE

        在MATCH或OPTIONAL MATCH中添加约束,或与WITH一起用来过滤结果。又叫“断言”,可以出现在查询的前,中,后

         示例:用方括号动态计算属性来过滤
         MATCH (n) WHERE n[toLower($prop)] < 30 RETURN n;
                                   
         示例:模式过滤
         MATCH (a),(b) WHERE (a)<--(b)RETURN a,b;            

        CASE

        • 简单式

           CASE test
           WHEN value THEN result
           [WHEN ...]
           [ELSE <default>]
           END
        • 搜索式

           CASE WHEN <predicate1> THEN result1
           CASE WHEN <predicate2> THEN result2
           [ELSE <default>]
           END

        START WITH

        字符串匹配,区分大小写,类似于SQL中的LIKE %。其余还有END WITH
        CONTAINS

        IS NULL

        测试一个值是否为空,相反为IS NOT NULL

        START

        使用遗留索引(Legacy Index)来查找,其他情况都应用MATCH

        • 通过索引搜索(Index Seek)开始点。 语法:node:<index_name>(key = "value")
          relationship:<index_name>(key = "value")

        • 通过索引查询(Index Query),语法node:<index_name>("query")
          relationship:<index_name>("query")
          。(使用复杂的Lucene语法)

        CREATE

        用于创建点和边。使用逗号分隔。注意创建边的前提是,首先要找到边的两个节点!使用CREATE时,模式中所有不存在的部分都会被创建

        示例:创建点

         CREATE (n)
         CREATE (n),(m)
         CREATE (n:Person),(m:Dog)
         CREATE (n:Person:Chinese)
         CREATE (n:Person {name:'Gaoj', age:'18'})                        

        示例:创建边

         //创建边
         MATCH (a:Person),(b:Person) WHERE a.name = 'Gaoj' AND b.name = 'Neoob'
         CREATE (a)-[r:RELATION1]->(b) RETURN a,b,r;
         
         //创建边,有属性name,属性由 + 拼接字符串
         MATCH (a:Person),(b:Person) WHERE a.name = 'Gaoj' AND b.name = 'Neoob'
         CREATE (a)<-[r:RELATION2 { name: a.name + ' 我是分隔符 ' + b.name }]-(b) RETURN a,b,r;

        MERGE

        创建某个Patten,MERGE=MATCH + CREATE,类似于SQL中的MERGE+UPDATE,即没有则创建有则什么都不做。使用MERGE要不整个Pattern被匹配,要么整个Pattern被创建,不会应用于部分Pattern。

        示例:MERGE与和MATCH+CREATE联合使用,类比SQL中的MERGE

         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

        可以使用唯一性约束+MARGE可以防止获取冲突的结果。

        SET

        用于更新/删除点和边的标签和属性。

        示例:修改点的标签

         MATCH (n:Boy {name:'gaoj'}) SET n:Gril:Chinese

        示例:使用+=
        添加属性

         MATCH (p {name: 'PeTER'}) SET p += {hungry: TRUE, position:'Begger'}

        DELETE

        删除点、边、路径。不能只删除点,而不删除与点相连的关系,要不显式的删除关系,要么使用DETACH DETELE
        隐式删除

        示例:删除一个点和其所有关系

         MATCH (n {name:'gaoj'}) DETACH DELETE n

        示例:删除所有点边(清空图)

         MATCH (n) DETACH DELETE n;

        REMOVE

        用于删除属性和标签。Neo4j中不允许属性存null值,如果属性真的为空值,则其属性会被删除。

        示例:删除属性

         MATCH (a {name: 'Andy'}) REMOVE a.age

        示例:删除多个标签

         MATCH (n:Chinese:German:Swedish {name: 'Peter'}) REMOVE n:German:Swedish

        FOREACH

        用于更新列表中的数据,或来自路径的组件,或者来自聚合的结果。它可以在集合或路径的每一个元素上执行更新命令。FOREACH中的变量是和外部分开的,类似游标。

        在FOREACH中可以执行任何UPDATE和CREATE, CREATE UNIQUE, DELETE , FOREACH。

        如果希望对列表里的元素执行额外的MATCH,使用UNWIND命令更合适。

        示例:更新路径,路径删的所有节点的marked属性设置为True

         MATCH p=(start)-[*]->(finish)
         WHERE start.name = 'A' AND finish.name = 'D'
         FOREACH (n IN nodes(p) | SET n.marked = true)

        示例:更新列表,将小红小明小白全部加为老王的好友

         MATCH (a:Person {name:"老王"})
         FOREACH (i in ["小红","小明","小白"] | CREATE (a) -[:FRIEND]->(:Person {name:name}))              

        CREATE UNIQUE

        匹配所有模式,创建不存在的。类似于MERGE,但是保证关系是唯一的,如果找到多个匹配的子图,那么CREATE UNIQUE会报错。

        RETURN

        定义查询结果集返回的内容。

        示例:返回所有

         MATCH p=(a {name:'A'}) -[r]->(b)
         RETURN *                              

        如果RETURN的属性不存在,可以正常查询,但是会返回Null

        ORDER BY

        紧跟 RETURN 和 WITH,用来给结果排序。能排序其属性,点都是无序的!默认升序,降序使用DESC

        注意:结果含null的情况,升序null会拍在最后,而降序null会排在最前

        LIMIT

        限制返回的行数,可用任意表达式,但必须是正整数。

        SKIP

        定义从哪行开始返回结果

        示例:

         MATCH (n) 
         RETURN n
         ORDER BY n.name
         SKIP 1
         LIMIT 3+1;      

        WITH

        将分段的查询连接在一起,传递给另外一部分作为查询的开始。

        1. 常用于限制传递给MATCH的结果数

        2. 通过ORDER和LIMIT,可获取前面的的结果

        3. 还可用于将图语句中的“读和写分开”

        示例1:过滤聚合结果

         MATCH (david {name: 'David'})--(otherPerson)-->()
         WITH otherPerson, count(*) AS foaf
         WHERE foaf > 1
         RETURN otherPerson.name

        示例2:获取后面的结果

         MATCH (n)
         WITH n
         ORDER BY n.name DESC
         LIMIT 3
         RETURN collect(n.name)
                       
         MATCH (n {name: 'Anders'})--(m)
         WITH m
         ORDER BY m.name DESC
         LIMIT 1
         MATCH (m)--(o)
         RETURN o.name              

        UNWIND

        将一个列表展开为一个序列的行。

        示例:list行去重

         WITH [1, 1, 2, 2, 2, 3] AS coll
         UNWIND coll AS x
         WITH DISTINCT x  //与DISTINCT联用
         RETURN collect(x) AS setOfVals //使用collect重新组装成list
         
         结果:[1,2,3]

        示例:列表拼接,列表拼接+去重

         //列表拼接
         WITH [1, 2, 3, 4] AS a, [3, 4, 5 ,6] AS b
         UNWIND (a + b) AS x
         return collect(x)
                       
         结果:[1, 2, 3, 4, 3, 4, 5, 6]
         
         //列表拼接+去重
         WITH [1, 2, 3, 4] AS a, [3, 4, 5 ,6] AS b
         UNWIND (a + b) AS x
         WITH DISTINCT x AS y
         return collect(y)
                       
         结果:[1, 2, 3, 4, 5, 6]
             
         //上面CQL可简写成
         WITH [1, 2, 3, 4] AS a, [3, 4, 5 ,6] AS b
         UNWIND (a + b) AS x
         RETURN collect(distinct x)      

        UNION

        将多个查询组合起来。和SQL类似,多个查询的列的名称和数量要一致!

        CALL

        调用SP。使用参数列表(逗号分隔)的形式给SP传参。

         CALL org.neo4j.procedure.example.addNodeToIndex('users', 0, 'name')

        四、函数

        id()

        where中使用,可查询节点,也可查询关系

         //使用id查询
         MATCH (n) WHERE id(n) = 123 RETURN n;

        type()

         //返回关系的类型
         //返回Reeves有关的电影名,和他在这个电影关系的类型(ACTION_IN)
         match (director {name:'Keanu Reeves'})-[r]-(movie) return distinct movie.title,type(r);

        shortestPath()  和 allShortestPaths()

         //返回最短路径,注意不是路径数
         MATCH (a:Person {name: 'Geena Davis'}),
         (b:Person {name: 'Keanu Reeves'}),
         p = shortestPath((a)-[*..15]-(b))
         RETURN p limit 1;
                         
         //返回所有最短路径  
         Finds all the shortest paths between two nodes      

        relationships()

         //返回模式中的所有关系
         MATCH (a:Person {name: 'Geena Davis'}),
         (b:Person {name: 'Keanu Reeves'}),
         p = shortestPath((a)-[*..15]-(b))
         RETURN relationships(p) limit 1;

        exists()

        检查点或边是否存在,原来的has()函数

         MATCH n WHERE exists(n.belt) WHERE n;

        正则表达式

        语法为Java的正则语法,使用~=
        ,放在正则表达式的开头。

        符号含义
        (?i)不区分大小写
        (?m)多行
        (?s)单行


        下面介绍聚合函数,类似SQL中的GROUP BY。

        COUNT()

        SUM()

        percentileDisc() 和 percentileCont()

        计算百分位,取值从0.0~1.0,使用舍入法取最接近的值。

         MATCH (n:Person) RETURN percentileDisc(n.age, 0.5);

        percentileCont同percentileDisc,使用线性插值,在两个数之间计算一个加权平均值。

        stdev() 和 stdevp()

        标准差。当以部分样本作为无偏估计时使用stdev,当计算整个样本的标准差是使用stdevp

        max() 和 min()

        最大最小值

        collect()

        所有值放进一个列表,null值被忽略,用于把行转成列

         MATCH (n:Person) RETURN collect(n.age)
         [11,31,34,66]                                

        distinct

        所有聚合函数都可以带DISTINCT去重

        load csv

        从CSV文件导入数据。fildterminator指定分隔符。

         using periodic commit 5000
         load csv from 'http://neo4j.docs./develober-manual/3.1/csv/artists-fieldterminator.csv' as line
         fieldterminator ';'
         create (:Artist {name: line[1], year: toInt(line[2])})

        五、性能调优

        • 在内存运行的情况下,尽量将查询部门链接在一起写

        • 使用参数来构建查询,可以让执行计划的缓存更加容易

        • 如果只查询属性,则尽量避免返回整个节点或关系

        (TO BE CONTINUED)


        文章转载自DCEGJ,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

        评论