CYPHER语言二

文章介绍了如何使用Cypher查询语言在图形数据库中进行数据过滤,包括匹配特定字符串、数值范围、属性存在性检查以及正则表达式的使用。通过案例展示了筛选电影数据集中演员、导演和电影信息的方法,如模糊搜索、范围查询和模式过滤。
摘要由CSDN通过智能技术生成

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一. 案例一:电影数据集

CREATE (matrix:Movie {title: 'The Matrix', released: 1997})
CREATE (cloudAtlas:Movie {title: 'Cloud Atlas', released: 2012})
CREATE (forrestGump:Movie {title: 'Forrest Gump', released: 1994})
CREATE (keanu:Person {name: 'Keanu Reeves', born: 1964})
CREATE (robert:Person {name: 'Robert Zemeckis', born: 1951})
CREATE (tom:Person {name: 'Tom Hanks', born: 1956})
CREATE (tom)-[:ACTED_IN {roles: ['Forrest']}]->(forrestGump)
CREATE (tom)-[:ACTED_IN {roles: ['Zachry']}]->(cloudAtlas)
CREATE (robert)-[:DIRECTED]->(forrestGump)

创建数据

筛选结果

到目前为止,你已经在图形中匹配了模式,并且总是返回你找到的所有结果。现在我们来看看过滤结果的选项,只返回你感兴趣的数据子集。

这些过滤条件用WHERE子句来表达。这个子句允许使用任何数量的布尔表达式、谓词,并结合AND、OR、XOR和NOT。最简单的谓词是比较;特别是平等。

MATCH (m:Movie)
WHERE m.title = 'The Matrix'
RETURN m

其他选项有数字比较、匹配正则表达式、以及检查列表中的值是否存在。

在下面的例子中,WHERE子句包括一个正则表达式匹配,一个大于比较,以及测试一个值是否存在于一个列表中。

MATCH (p:Person)-[r:ACTED_IN]->(m:Movie)
WHERE p.name =~ 'K.+' OR m.released > 2000 OR 'Neo' IN r.roles
RETURN p, r, m

一个先进的方面是,模式可以作为谓语使用。MATCH扩展了所匹配模式的数量和形状,而模式谓语则限制了当前的结果集。它只允许满足指定模式的路径通过。正如你所期望的,使用NOT只允许不满足指定模式的路径通过。

MATCH (p:Person)-[:ACTED_IN]->(m)
WHERE NOT (p)-[:DIRECTED]->()
RETURN p, m

查询值的范围

经常有一些查询,你想在某个范围内寻找数据。日期或数字范围可以用来检查某个时间轴内的事件,年龄值,或其他用途。

这个标准的语法与SQL和其他编程语言检查数值范围的逻辑结构非常相似。

下面的数据集是用来演示这些情况下的Cypher查询的。

MATCH (p:Person)
WHERE 3 <= p.yearsExp <= 7
RETURN p

测试属性值的存在

你可能只对某个节点或关系上存在的属性感兴趣。例如,你可能想检查你的系统中哪些客户有Twitter手柄,这样你就可以显示相关内容。或者,你可以检查你所有的员工是否有一个开始日期的属性,以验证哪些实体可能需要更新。

记住:在Neo4j中,一个属性只有在有值的情况下才存在(被存储)。空属性不会被存储。这可以确保只有有价值的、必要的信息才会被保留在你的节点和关系中。
要在Neo4j v5中编写这种类型的存在性检查,你需要使用IS NOT NULL谓词来只包括属性存在的节点或关系。

Cypher代码写在下面的块中。

//Query1: find all users who have a birthdate property
MATCH (p:Person)
WHERE p.birthdate IS NOT NULL
RETURN p.name;

//Query2: find all WORKS_FOR relationships that have a startYear property
MATCH (p:Person)-[rel:WORKS_FOR]->(c:Company)
WHERE rel.startYear IS NOT NULL
RETURN p, rel, c;

检查字符串 - 部分值,模糊搜索

有些场景需要查询语法,在一个字符串中对部分值或大类进行匹配。为了进行这种查询,你需要一些灵活性和选项来进行字符串匹配和搜索。无论你是在寻找一个以某一数值开始,以某一数值结束,还是包括某一数值的字符串,Cypher都提供了有效和容易处理的能力。

在Cypher中,有几个关键字与WHERE子句一起使用,用于测试字符串属性值。STARTS WITH关键字允许你检查以你指定的字符串开始的属性值。通过CONTAINS关键字,你可以检查一个指定的字符串是否是属性值的一部分。ENDS_WITH 关键字可以检查你指定的属性字符串的结尾。

下面的Cypher块中有一个各自的例子。

//check if a property starts with 'M'
MATCH (p:Person)
WHERE p.name STARTS WITH 'M'
RETURN p.name;

//check if a property contains 'a'
MATCH (p:Person)
WHERE p.name CONTAINS 'a'
RETURN p.name;

//check if a property ends with 'n'
MATCH (p:Person)
WHERE p.name ENDS WITH 'n'
RETURN p.name;
//check if a property starts with 'M'
MATCH (p:Person)
WHERE p.name STARTS WITH 'M'
RETURN p.name;

//check if a property contains 'a'
MATCH (p:Person)
WHERE p.name CONTAINS 'a'
RETURN p.name;

//check if a property ends with 'n'
MATCH (p:Person)
WHERE p.name ENDS WITH 'n'
RETURN p.name;

你也可以使用正则表达式来测试字符串的值。例如,你可以寻找所有共享一个名字的人的节点,或者你可以找到所有具有某个部门代码的班级。

让我们看一个例子。

MATCH (p:Person)
WHERE p.name =~ 'Jo.*'
RETURN p.name

就像在SQL和其他语言中,你可以检查一个属性值是否是一个列表中的值。IN关键字允许你指定一个值的数组,并根据列表中的每一个值来验证一个属性的内容。

下面是一个例子。

MATCH (p:Person)
WHERE p.yearsExp IN [1, 5, 6]
RETURN p.name, p.yearsExp

对模式进行过滤

使graph独特的一点是它对关系的关注。就像你可以根据节点标签或属性来过滤查询一样,你也可以根据关系或模式来过滤结果。这允许你测试一个模式是否也有某种关系,或者是否存在另一种模式。

下面的Cypher代码显示了这是如何做到的。

//Query1: find which people are friends of someone who works for Neo4j
MATCH (p:Person)-[r:IS_FRIENDS_WITH]->(friend:Person)
WHERE exists((p)-[:WORKS_FOR]->(:Company {name: 'Neo4j'}))
RETURN p, r, friend;

//Query2: find Jennifer's friends who do not work for a company
MATCH (p:Person)-[r:IS_FRIENDS_WITH]->(friend:Person)
WHERE p.name = 'Jennifer'
AND NOT exists((friend)-[:WORKS_FOR]->(:Company))
RETURN friend.name;

可选的模式
在有些情况下,你可能想从模式中检索结果,即使它们不符合整个模式或所有的标准。这就是SQL中外层连接的功能。在Cypher中,你可以使用一个OPTIONAL MATCH模式来尝试匹配它,但是如果它没有找到结果,这些行的值将返回null。

你可以通过查询名字以特定字母开头的人和可能在某公司工作的人,来看看这在Cypher中会是什么样子。

//Find all people whose name starts with J and who may work for a company.
MATCH (p:Person)
WHERE p.name STARTS WITH 'J'
OPTIONAL MATCH (p)-[:WORKS_FOR]-(other:Company)
RETURN p.name, other.name;

返回结果

到目前为止,你已经直接通过它们的变量返回了节点、关系和路径。然而,RETURN子句可以返回任何数量的表达式。但是Cypher中的表达式是什么?

最简单的表达式是字面值。字面值的例子有:数字、字符串、数组(例如:[1,2,3])和maps(例如。{name:‘Tom Hanks’, born:1964, movies: [‘Forrest Gump’, …], count: 13}).

任何节点、关系或地图的单个属性都可以使用点语法进行访问,例如:n.name。

数组的单个元素或片断可以用下标来检索,例如:names[0]和movies[1…-1]。

每个函数评估,例如:length(array), toInteger(‘12’), substring(‘2014-07-01’, 0, 4) 和 coalesce(p.nickname, ‘n/a’),也是一个表达式。

在WHERE子句中使用的谓词也算作布尔表达式。

简单的表达式可以被组成和串联以形成更复杂的表达式。

默认情况下,表达式本身被用作列的标签,在很多情况下,你想用表达式AS别名来表示一个更容易理解的名字。这个别名可以在以后用来指代该列。

在WHERE子句中使用的谓词也算作布尔表达式。

简单的表达式可以被组成和串联以形成更复杂的表达式。

默认情况下,表达式本身被用作列的标签,在很多情况下,你想用表达式AS别名来表示一个更容易理解的名字。这个别名可以在以后用来指代该列。

MATCH (p:Person)
RETURN
  p,
  p.name AS name,
  toUpper(p.name),
  coalesce(p.nickname, 'n/a') AS nickname,
  {name: p.name, label: head(labels(p))} AS person

如果你希望只显示唯一的结果,你可以在RETURN后面使用DISTINCT关键字。

MATCH (n)
RETURN DISTINCT labels(n) AS Labels

你可以使用Cypher中的DISTINCT关键字返回唯一的结果。你的一些查询可能会返回重复的结果,这是因为通往节点的多个路径或一个节点满足多个标准。这种冗余会使结果杂乱无章,并使筛选一个长长的列表很难找到你需要的东西。

为了修剪出重复的实体,你可以使用DISTINCT关键字。

//Query: find people who have a twitter or like graphs or query languages
MATCH (user:Person)
WHERE user.twitter IS NOT null
WITH user
MATCH (user)-[:LIKES]-(t:Technology)
WHERE t.type IN ['Graphs','Query Languages']
RETURN DISTINCT user.name

有些时候,你想要一个抽样集,或者你只想一次拉出这么多结果来更新或处理。LIMIT关键字可以获取查询的输出结果,并根据你指定的数量来限制返回的数量。

例如,你可以在我们的图中找到每个人的朋友数量。如果该图有数千或数百万的节点和关系,返回的结果数量将是巨大的。如果你只关心拥有最多的朋友的前三个人呢?让我们为之写一个查询!

//Query: find the top 3 people who have the most friends
MATCH (p:Person)-[r:IS_FRIENDS_WITH]-(other:Person)
RETURN p.name, count(other.name) AS numberOfFriends
ORDER BY numberOfFriends DESC
LIMIT 3

信息聚合

在很多情况下,我们希望对在图中遍历模式时遇到的数据进行聚合或分组。在Cypher中,聚合发生在计算最终结果时的RETURN子句中。许多常见的聚合函数都被支持,例如count、sum、avg、min和max,但还有其他一些函数。

计算你的电影数据库中的人数可以通过这个来实现。

MATCH (:Person)
RETURN count(*) AS people

注意,在聚合过程中会跳过NULL值。对于只聚合唯一的值,使用DISTINCT,例如:count(DISTINCT role)。

聚合在Cypher中是隐含的。你指定哪些结果列是你希望聚合的。Cypher使用所有未聚合的列作为分组键。

聚合会影响到哪些数据在排序或以后的查询部分仍然可见。

收集聚合

一个非常有用的聚合函数是 collect(expression),它返回一个由表达式返回的单个聚合列表的值。这在很多情况下都非常有用,因为在聚合时不会丢失任何细节信息。

collect()非常适用于检索典型的父子结构,每行返回一个核心实体(父、根或头),其所有附属信息都在用collect()创建的相关列表中。这意味着不需要为每条子行重复父系信息,也不需要运行n+1条语句来单独检索父系和子系。

下面的语句可以用来检索我们数据库中每部电影的演员。

MATCH (m:Movie)<-[:ACTED_IN]-(a:Person)
RETURN m.title AS movie, collect(a.name) AS cast, count(*) AS actors

循环浏览列表中的值

如果你有一个你想检查或分离的列表,Cypher提供了UNWIND子句。这个子句与collect()相反,它将一个列表分离成独立的行中的单个值。

UNWIND经常被用来在导入数据时循环浏览JSON和XML对象,以及日常数组和其他类型的列表。让我们看几个例子,我们假设某人喜欢的技术也意味着他们对每个技术都有一些经验。如果你有兴趣雇用熟悉图形或查询语言的人,你可以写下面的查询来寻找要面试的人。

//Query1: for a list of techRequirements, look for people who have each skill
WITH ['Graphs','Query Languages'] AS techRequirements
UNWIND techRequirements AS technology
MATCH (p:Person)-[r:LIKES]-(t:Technology {type: technology})
RETURN t.type, collect(p.name) AS potentialCandidates;
//Query2: for numbers in a list, find candidates who have that many years of experience
WITH [4, 5, 6, 7] AS experienceRange
UNWIND experienceRange AS number
MATCH (p:Person)
WHERE p.yearsExp = number
RETURN p.name, p.yearsExp;

排序

在使用count(x)进行汇总后,通常会进行排序和分页。

排序是使用ORDER BY表达式[ASC|DESC]子句完成的。这个表达式可以是任何表达式,只要它可以从返回的信息中计算出来。

例如,如果你返回person.name,你仍然可以ORDER BY person.age,因为两者都可以从person引用中获得。你不能用没有返回的东西排序。这一点对于聚合和DISTINCT返回值来说特别重要,因为两者都会消除被聚合的数据的可见性。

分页是使用SKIP {offset}和LIMIT {count}子句完成的。

一个常见的模式是对一个计数(分数或频率)进行聚合,按其排序,并只返回前n个条目。

例如,要找到最多产的演员,你可以这样做。

MATCH (a:Person)-[:ACTED_IN]->(m:Movie)
RETURN a, count(*) AS appearances
ORDER BY appearances DESC LIMIT 10
//Query1: for a list of techRequirements, look for people who have each skill
WITH ['Graphs','Query Languages'] AS techRequirements
UNWIND techRequirements AS technology
MATCH (p:Person)-[r:LIKES]-(t:Technology {type: technology})
WITH t.type AS technology, p.name AS personName
ORDER BY technology, personName
RETURN technology, collect(personName) AS potentialCandidates;

size计算列表内数据条数

//Query1: find number of items in collected list
MATCH (p:Person)-[:IS_FRIENDS_WITH]->(friend:Person)
RETURN p.name, size(collect(friend.name)) AS numberOfFriends;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值