密码查询语言简介

查询语言Cypher最初是专门为图形 DBMS Neo4j开发的 。 Cypher的目标是为图形数据库提供一种人类可读的SQL数据库查询语言。 如今,Cypher得到了几种图形DBMS的支持。 OpenCypher的创建是为了标准化Cypher。


在浏览器中使用Neo4j的基础知识文章中描述了使用Neo4j DBMS的基础知识


为了使自己熟悉Cypher,请考虑一本从I. Bratko的经典Prolog教科书中借来的家谱的例子。 此示例将说明如何向图添加节点和链接,如何为它们分配标签和属性以及如何提出问题。


Neo4j中的家谱,已编辑视图


因此,让我们在下图中显示一棵家谱。


家谱


让我们看看如何在Cypher中形成相应的图形:


CREATE (pam:Person {name: "Pam"}), (tom:Person {name: "Tom"}), (kate:Person {name: "Kate"}), (mary:Person {name: "Mary"}), (bob:Person {name: "Bob"}), (liz:Person {name: "Liz"}), (dick:Person {name: "Dick"}), (ann:Person {name: "Ann"}), (pat:Person {name: "Pat"}), (jack:Person {name: "Jack"}), (jim:Person {name: "Jim"}), (joli:Person {name: "Joli"}), (pam)-[:PARENT]->(bob), (tom)-[:PARENT]->(bob), (tom)-[:PARENT]->(liz), (kate)-[:PARENT]->(liz), (mary)-[:PARENT]->(ann), (bob)-[:PARENT]->(ann), (bob)-[:PARENT]->(pat), (dick)-[:PARENT]->(jim), (ann)-[:PARENT]->(jim), (pat)-[:PARENT]->(joli), (jack)-[:PARENT]->(joli) 

将数据添加到图形DBMS的CREATE请求由两部分组成:添加节点以及在它们之间添加链接。 在此请求的框架内,将为每个要添加的节点分配一个名称,然后将其用于创建链接。 节点和通信可以存储文档。 在我们的例子中,节点包含带有名称字段的文档,而文档链接不包含。 还可以标记节点和链接。 在我们的例子中,节点被分配标签为Person,链接为PARENT。 请求中的标签在名称前用冒号突出显示。


因此,Neo4j告诉我们: Added 12 labels, created 12 nodes, set 12 properties, created 11 relationships, completed after 9 ms.


让我们看看我们得到了什么:


 MATCH (p:Person) RETURN p 

Neo4j中的家谱


没有人禁止我们编辑结果图的外观:


Neo4j中的家谱,已编辑视图


该怎么办? 您可以验证,例如,Pam是
鲍勃的父母:


 MATCH ans = (:Person {name: "Pam"})-[:PARENT]->(:Person {name: "Bob"}) RETURN ans 

我们得到相应的子图:


帕姆是鲍勃的父母


但是,这并不是我们真正需要的。 更改请求:


 MATCH ans = (:Person {name: "Pam"})-[:PARENT]->(:Person {name: "Bob"}) RETURN ans IS NOT NULL 

现在,我们得到了回应。 如果我们问:


 MATCH ans = (:Person {name: "Pam"})-[:PARENT]->(:Person {name: "Liz"}) RETURN ans IS NOT NULL 

我们什么都不会得到。。。在这里您需要添加单词OPTIONAL ,然后如果
结果为空,然后返回false


 OPTIONAL MATCH ans = (:Person {name: "Pam"})-[:PARENT]->(:Person {name: "Liz"}) RETURN ans IS NOT NULL 

现在我们得到预期的答案为false


接下来,您可以看到谁是谁的父母:


 MATCH (p1:Person)-[:PARENT]->(p2:Person) RETURN p1, p2 

使用“ Text打开结果选项卡,然后查看包含两列的表:


 ╒═══════════════╤═══════════════╕ │"p1" │"p2" │ ╞═══════════════╪═══════════════╡ │{"name":"Pam"} │{"name":"Bob"} │ ├───────────────┼───────────────┤ │{"name":"Tom"} │{"name":"Bob"} │ ├───────────────┼───────────────┤ │{"name":"Tom"} │{"name":"Liz"} │ ├───────────────┼───────────────┤ │{"name":"Kate"}│{"name":"Liz"} │ ├───────────────┼───────────────┤ │{"name":"Mary"}│{"name":"Ann"} │ ├───────────────┼───────────────┤ │{"name":"Bob"} │{"name":"Ann"} │ ├───────────────┼───────────────┤ │{"name":"Bob"} │{"name":"Pat"} │ ├───────────────┼───────────────┤ │{"name":"Dick"}│{"name":"Jim"} │ ├───────────────┼───────────────┤ │{"name":"Ann"} │{"name":"Jim"} │ ├───────────────┼───────────────┤ │{"name":"Pat"} │{"name":"Joli"}│ ├───────────────┼───────────────┤ │{"name":"Jack"}│{"name":"Joli"}│ └───────────────┴───────────────┘ 

我们还能学到什么? 例如,谁是属的特定成员的父母,例如Bob:


 MATCH (parent:Person)-[:PARENT]->(:Person {name: "Bob"}) RETURN parent.name 

 ╒═════════════╕ │"parent.name"│ ╞═════════════╡ │"Tom" │ ├─────────────┤ │"Pam" │ └─────────────┘ 

在这里,作为答案,我们不请求整个节点,而仅请求其特定属性。


我们还可以找出鲍勃的孩子是谁:


 MATCH (:Person {name: "Bob"})-[:PARENT]->(child:Person) RETURN child.name 

 ╒════════════╕ │"child.name"│ ╞════════════╡ │"Ann" │ ├────────────┤ │"Pat" │ └────────────┘ 

我们也可以问谁有孩子:


 MATCH (parent:Person)-[:PARENT]->(:Person) RETURN parent.name 

 ╒═════════════╕ │"parent.name"│ ╞═════════════╡ │"Pam" │ ├─────────────┤ │"Tom" │ ├─────────────┤ │"Tom" │ ├─────────────┤ │"Kate" │ ├─────────────┤ │"Mary" │ ├─────────────┤ │"Bob" │ ├─────────────┤ │"Bob" │ ├─────────────┤ │"Dick" │ ├─────────────┤ │"Ann" │ ├─────────────┤ │"Pat" │ ├─────────────┤ │"Jack" │ └─────────────┘ 

嗯,汤姆和鲍勃相遇了两次,解决了这个问题:


 MATCH (parent:Person)-[:PARENT]->(:Person) RETURN DISTINCT parent.name 

我们在查询的返回结果中添加了单词DISTINCT ,这意味着
与SQL中的类似。


 ╒═════════════╕ │"parent.name"│ ╞═════════════╡ │"Pam" │ ├─────────────┤ │"Tom" │ ├─────────────┤ │"Kate" │ ├─────────────┤ │"Mary" │ ├─────────────┤ │"Bob" │ ├─────────────┤ │"Dick" │ ├─────────────┤ │"Ann" │ ├─────────────┤ │"Pat" │ ├─────────────┤ │"Jack" │ └─────────────┘ 

您可能还会注意到Neo4j按照在CREATE请求中输入的顺序将父母退还给我们。


现在让我们问谁是祖父或祖母:


 MATCH (grandparent:Person)-[:PARENT]->()-[:PARENT]->(:Person) RETURN DISTINCT grandparent.name 

太好了,就是这样:


 ╒══════════════════╕ │"grandparent.name"│ ╞══════════════════╡ │"Tom" │ ├──────────────────┤ │"Pam" │ ├──────────────────┤ │"Bob" │ ├──────────────────┤ │"Mary" │ └──────────────────┘ 

在查询模板中,我们使用了一个中间的无名节点()和两个类型为PARENT关系。


现在我们找出谁是父亲。 父亲是一个有孩子的男人。 因此,我们缺乏有关该男子是谁的数据。 因此,要确定谁是母亲,您需要知道谁是女人。 将相关信息添加到我们的数据库中。 为此,我们将标签MaleFemale分配给现有节点。


 MATCH (p:Person) WHERE p.name IN ["Tom", "Dick", "Bob", "Jim", "Jack"] SET p:Male 

 MATCH (p:Person) WHERE p.name IN ["Pam", "Kate", "Mary", "Liz", "Ann", "Pat", "Joli"] SET p:Female 

让我们解释一下我们在这里所做的事情:我们选择了所有标有Person节点,并选中了它们
根据在方括号中指定的给定列表指定name属性,并分别为相应的节点分配标签MaleFemale


检查:


 MATCH (p:Person) WHERE p:Male RETURN p.name 

 ╒════════╕ │"p.name"│ ╞════════╡ │"Tom" │ ├────────┤ │"Bob" │ ├────────┤ │"Dick" │ ├────────┤ │"Jack" │ ├────────┤ │"Jim" │ └────────┘ 

 MATCH (p:Person) WHERE p:Female RETURN p.name 

 ╒════════╕ │"p.name"│ ╞════════╡ │"Pam" │ ├────────┤ │"Kate" │ ├────────┤ │"Mary" │ ├────────┤ │"Liz" │ ├────────┤ │"Ann" │ ├────────┤ │"Pat" │ ├────────┤ │"Joli" │ └────────┘ 

我们请求所有标记为Person节点,每个节点也分别标记为MaleFemale 。 但是我们可以使我们的请求有所不同:


 MATCH (p:Person:Male) RETURN p.name MATCH (p:Person:Female) RETURN p.name 

让我们再次看一下我们的图:


带有标签男性和女性的家谱


Neo4j Browser根据Male和Mark的标记以两种不同的颜色绘制节点
女款


好的,现在我们可以从数据库中查询所有父亲:


 MATCH (p:Person:Male)-[:PARENT]->(:Person) RETURN DISTINCT p.name 

 ╒════════╕ │"p.name"│ ╞════════╡ │"Tom" │ ├────────┤ │"Bob" │ ├────────┤ │"Dick" │ ├────────┤ │"Jack" │ └────────┘ 

和母亲:


 MATCH (p:Person:Female)-[:PARENT]->(:Person) RETURN DISTINCT p.name 

 ╒════════╕ │"p.name"│ ╞════════╡ │"Pam" │ ├────────┤ │"Kate" │ ├────────┤ │"Mary" │ ├────────┤ │"Ann" │ ├────────┤ │"Pat" │ └────────┘ 

现在让我们建立一个兄弟姐妹关系。 X是Y的兄弟,
如果他是男人,并且对于X和Y,至少有一个共同的父母。 同样的
关系姐姐。


兄弟对密码的态度:


 MATCH (brother:Person:Male)<-[:PARENT]-()-[:PARENT]->(p:Person) RETURN brother.name, p.name 

 ╒══════════════╤════════╕ │"brother.name"│"p.name"│ ╞══════════════╪════════╡ │"Bob" │"Liz" │ └──────────────┴────────┘ 

Cypher的姐妹态度:


 MATCH (sister:Person:Female)<-[:PARENT]-()-[:PARENT]->(p:Person) RETURN sister.name, p.name 

 ╒═════════════╤════════╕ │"sister.name"│"p.name"│ ╞═════════════╪════════╡ │"Liz" │"Bob" │ ├─────────────┼────────┤ │"Ann" │"Pat" │ ├─────────────┼────────┤ │"Pat" │"Ann" │ └─────────────┴────────┘ 

因此,我们可以找出谁是谁的父母,以及谁是谁的祖父或祖母。 但是,更远的祖先呢? 有曾祖父,曾曾祖父等等? 我们不会为每种情况编写相应的规则,并且每次都会有更多问题。 实际上,一切都很简单:如果X是父Y的祖先,则X是Y的祖先。Cypher提供了一个模式* ,允许您要求一个任意长度的关系序列:


 MATCH (p:Person)-[*]->(s:Person) RETURN DISTINCT p.name, s.name 

确实存在一个问题:将是任何连接。 添加对PARENT链接的引用:


 MATCH (p:Person)-[:PARENT*]->(s:Person) RETURN DISTINCT p.name, s.name 

为了不增加文章的篇幅,我们找到了Joli所有祖先:


 MATCH (p:Person)-[:PARENT*]->(:Person {name: "Joli"}) RETURN DISTINCT p.name 

 ╒════════╕ │"p.name"│ ╞════════╡ │"Jack" │ ├────────┤ │"Pat" │ ├────────┤ │"Bob" │ ├────────┤ │"Pam" │ ├────────┤ │"Tom" │ └────────┘ 

考虑一个更复杂的规则,以找出与谁相关的人。
首先,亲戚是祖先和后代,例如儿子和母亲,祖母和孙子。 其次,亲戚是兄弟姐妹,包括堂兄弟姐妹,第二堂兄弟姐妹等等,就祖先而言,这意味着他们拥有共同的祖先。 第三,具有共同后代的亲戚,例如丈夫和妻子,被视为亲戚。


在Cypher上,您需要对多种模式使用UNION


 MATCH (r1:Person)-[:PARENT*]-(r2:Person) RETURN DISTINCT r1.name, r2.name UNION MATCH (r1:Person)<-[:PARENT*]-(:Person)-[:PARENT*]->(r2:Person) RETURN DISTINCT r1.name, r2.name UNION MATCH (r1:Person)-[:PARENT*]->(:Person)<-[:PARENT*]-(r2:Person) RETURN DISTINCT r1.name, r2.name 

在这里,第一条规则是使用连接,连接的方向对我们而言无关紧要。 这样的连接用箭头表示,而不是短划线- 。 第二和第三条规则以显而易见的熟悉方式编写。


我们不会在这里显示总查询的结果,我们只会说找到的亲戚对是132,这与计算值一致,即从12开始的有序对的数量。我们也可以通过将变量r1r2的出现替换为(:Person {name: "Liz"}) ,但是,在我们的案例中,这没有多大意义,因为数据库中的所有人显然都是亲戚。


到此,我们结束了在数据库中识别人与人之间关系的讨论。


最后,考虑如何删除节点和链接。


要删除我们所有人,您可以执行以下请求:


 MATCH (p:Person) DELETE p 

但是,Neo4j将告诉我们您不能删除具有链接的节点。
因此,我们首先删除链接,然后重复删除节点:


 MATCH (p1:Person)-[r]->(p2:Person) DELETE r 

现在我们要做的事情:比较两个有连接的人,将此连接命名为r ,然后将其删除。


结论


本文通过一个简单的社交图示例显示了如何使用Cypher查询语言的功能。 特别是,我们研究了如何通过一个查询添加节点和链接,如何搜索相关数据(包括间接链接)以及如何为节点分配标签。 有关Cypher的更多信息,请参见下面的链接。 一个很好的起点是“ Neo4j Cypher Refcard”。


Neo4j远非唯一的图形DBMS。 在其他最受欢迎的软件中,包括Cayley ,具有GraphQL查询语言的Dgraph,多模型ArangoDBOrientDB 。 尤其受关注的Blazegraph支持RDF和SPARQL。


参考文献



参考书目


  • 鲁滨逊·扬,韦伯·吉姆,埃弗雷姆·埃米尔。 图形数据库。 新功能
    用于处理相关数据/ Per。 来自英语 -第二版 -M。:DMK-Press,
    2016-256秒
  • Bratko I.使用Prolog语言进行人工智能编程:
    反式 来自英语 -M .:米尔(Mir),1990年。-560羽。

后记


本文的作者仅知道两家公司(都来自圣彼得堡)在其产品中使用图形DBMS。 但是我想知道本文的读者中有多少家公司在开发过程中使用它们。 因此,我建议参加调查。 在评论中也写您的经历,这将非常有趣。

Source: https://habr.com/ru/post/zh-CN482418/


All Articles