GQL 查询模式、示例和常见方案(预览版)

本文提供图形查询语言示例,重点介绍核心查询模式,并展示使用真实图形架构和查询的 GQL 常见实际用例。

以下示例显示了从简单模式到复杂模式支持的 GQL 语法。

注释

在尝试这些示例之前,请设置环境以使用 GQL。 有关详细信息,请参阅 “入门 ”。 确保将客户端请求属性设置为使用 GQL,并将图形引用函数设置为图形数据源。

GQL 支持处于 预览状态。 功能和语法可能会根据反馈和正在进行的开发而变化。

核心 GQL 查询模式

比赛

有关受支持的 GQL 函数和运算符的完整列表,请参阅 图形查询语言 (GQL) 参考

基本模式匹配示例

没有变量的基本模式匹配

最简单的模式匹配任何关系,而无需引用匹配的值。

MATCH ()-[]-()
RETURN COUNT(*)

此查询查找关系图中的所有关系。 空括号 () 表示匿名节点,并 [] 表示匿名边缘。 由于我们不分配变量,因此只能对匹配项进行计数,但无法访问其属性。

与变量的模式匹配

若要访问匹配的节点和边缘,请将其分配给变量。

MATCH (n)-[e]->(n2)
RETURN COUNT(*)

n 表示源节点, e 表示 定向 边缘,并 n2 表示目标节点。 引用这些变量来访问属性,但在此示例中,你仍仅对匹配项进行计数。

访问节点属性

获得变量后,可以访问匹配节点的属性。

MATCH (person)-[e]->(target)
RETURN person.name, target.name, e.lbl
ORDER BY person.name
LIMIT 2

输出

此查询返回连接实体的名称及其之间的关系类型,按 person.name 排序,并限制为两个结果来管理输出大小。 虽然这些实体已命名 person ,但 target没有任何限制可以确保它们实际上是一个人。

person.name target.name e.lbl
爱丽丝 TechCorp works_at
爱丽丝 Seattle located_at

按节点标签进行筛选

使用标签匹配特定类型的节点。 在变量名称后面指定带冒号的标签。

MATCH (person:Person)
RETURN person.name
ORDER BY person.name
LIMIT 5

输出

此查询仅匹配具有“Person”标签的节点并返回其名称,限制为五个结果以避免大型结果集。

person.name
爱丽丝
鲍勃
颂歌
大卫
艾玛

按边缘标签进行筛选

MATCH (person:Person)-[works:works_at]->(company:Company)
RETURN person.name, company.name

按不带变量的边缘标签进行筛选

对于此示例,请切换回具有“知道”关系的原始G_Doc_Transient() 图:

#crp query_graph_reference=G_Doc_Transient()

无需在不需要访问其属性时按边缘标签进行筛选,而无需将边缘分配给变量。

MATCH (p1:Person)-[:knows]->(p2:Person)
RETURN p1.name, p2.name
ORDER BY p1.name

输出

此查询通过“知道”关系查找连接到其他 Person 节点的人员节点。 边缘按标签进行筛选,但未分配给变量,因为你只需要连接的节点。

p1.name p2.name
爱丽丝 鲍勃
鲍勃 颂歌
颂歌 大卫
大卫 艾玛

使用 WHERE 按属性进行筛选

使用 WHERE 子句根据属性值进行筛选。

MATCH (person:Person)
WHERE person.properties.age > 25
RETURN person.name, person.properties.age

此查询查找 25 岁以上的人,并返回其姓名和年龄。 WHERE 子句按 age 属性筛选匹配的节点。

内联属性筛选器

使用内联条件直接按模式中的属性进行筛选。

MATCH (person:Person {name: 'Bob'})
RETURN person.properties.age

此查询查找名为“Bob”的人员并返回其年龄。 语法 {name: 'Bob'} 筛选名称属性等于“Bob”的节点。

多个内联条件

内联指定多个属性条件。

MATCH (person:Person {name: 'Bob'})
WHERE person.properties.age = 30
RETURN person as Bob

此查询查找具有指定名称和年龄的人员。 它将人员节点返回为“Bob”。

可变长度路径

对多跃点关系使用具有限定符的可变长度路径模式:

MATCH (s)-[]->{1,3}(e)
RETURN s.name, e.name

此查询查找包含 1 到 3 个跃点的路径。 {1,3}限定符设置最小和最大路径长度。

未绑定的可变长度路径

指定可变长度路径的开放范围:

MATCH (center)-[]->{1,}(connected)
WHERE center.name = 'Alice'
RETURN DISTINCT connected.name

此查询查找可通过一个或多个跃点的路径从 Alice 访问的所有节点。 {1,}限定符表示“一个或多个跃点”。

路径函数

使用路径函数提取有关匹配路径的信息,包括构成路径的节点和关系:

MATCH fof = (person)-[:knows]->{2,2}()
RETURN fof, NODES(fof) AS NodesOfPath, RELATIONSHIPS(fof) AS EdgesOfPath
LIMIT 1

此查询使用“知道”关系查找长度正好为 2 个跃点的路径。 路径变量 fof 包含整个路径作为交替节点和边缘的数组。 该 NODES() 函数仅从路径中提取节点,并 RELATIONSHIPS() 仅提取边缘。

输出

fof NodesOfPath EdgesOfPath
[{"id": "p3", "lbl": "Person", "name": "Carol", "properties": {"age": 28}, "$labels": ["Person"]}, {"source": "p3", "target": "p4", "lbl": "knows", "since": 2022, "$labels": ["knows"]}, {"id": "p4", "lbl": "Person", "name": "David", "properties": {"age": 35}, "$labels": ["Person"]}, {"source": "p4", "target": "p5", "lbl": "knows", "since": 2023, "$labels": ["knows"]}, {"id": "p5", "lbl": "Person", "name": "Emma", "properties": {"age": 26}, "$labels": ["Person"]}] [{"id": "p3", "lbl": "Person", "name": "Carol", "properties": {"age": 28}, "$labels": ["Person"]}, {"id": "p4", "lbl": "Person", "name": "David", "properties": {"age": 35}, "$labels": ["Person"]}, {"id": "p5", "lbl": "Person", "name": "Emma", "properties": {"age": 26}, "$labels": ["Person"]}] [{"source": "p3", "target": "p4", "lbl": "knows", "since": 2022, "$labels": ["knows"]}, {"source": "p4", "target": "p5", "lbl": "knows", "since": 2023, "$labels": ["knows"]}]

基本属性筛选

基于单个属性条件筛选节点:

MATCH (person:Person)
WHERE person.properties.age > 26
RETURN person.name, person.properties.age
ORDER BY person.name

输出

此查询查找属性大于 26 的所有 Person 节点 age

person.name person.properties.age
鲍勃 30
颂歌 28
大卫 35

使用 AND 筛选范围

若要创建范围,请组合多个条件:

MATCH (person:Person)
WHERE person.properties.age >= 28 AND person.properties.age <= 35
RETURN person.name, person.properties.age

此查询显示年龄在 28 到 35 岁(含)之间的人员。

Edge 属性筛选

按边缘属性进行筛选以查找特定类型的关系。

MATCH (person:Person)-[wa:works_at]->(c:Company)
WHERE wa.since >= 2022
RETURN person.name, c.name, wa.since

此查询显示 2022 年或更高版本开始在公司工作的人员。 它按 since 关系的属性 works_at 进行筛选。

字符串模式匹配

使用字符串函数匹配文本模式。

MATCH (person:Person)
WHERE person.name STARTS WITH 'Al'
RETURN COUNT(*)

此查询统计名称以“Al”开头的人。 它提供快速摘要,无需返回大型结果集。

字符串包含匹配

检查字符串是否具有特定的子字符串。

MATCH (person:Person)
WHERE person.name CONTAINS 'i'
RETURN person.name

此查询查找名称在字符串中的任何位置都有“i”的人员。 此匹配区分大小写。

不等比较

使用比较运算符排除特定值:

MATCH (person:Person)-[wa:works_at]->(company:Company)
WHERE person.properties.age > 25 AND company.name <> 'TechCorp'
RETURN person.name, company.name

此查询显示超过 25 名在“TechCorp”以外的公司工作的人员。

Null 值检查

检查是否存在属性值。

MATCH (person:Person)
WHERE person.properties.age IS NOT NULL
RETURN person.name, person.properties.age

此查询查找记录了年龄的所有人员(非 null 年龄属性)。

逻辑 OR作

使用 OR 匹配多个条件

MATCH (person:Person)
WHERE person.properties.age > 30 OR person.name CONTAINS 'a'
RETURN person.name, person.properties.age

此查询查找年龄超过 30 岁或姓名为“a”的人员。

返回特定属性

从匹配的节点返回单个属性。

MATCH (person:Person)
RETURN person.name, person.properties.age

此查询返回每个 Person 节点的名称和年龄属性。 结果中的每个行都显示这两个值。

使用别名返回

为了清楚起见,请使用别名重命名输出列。

MATCH (person:Person)-[employment:works_at]->(company:Company)
RETURN person.name AS Employee, company.name AS Company, employment.since AS WorkingSince

此查询返回具有描述性列标题的员工姓名、公司名称和就业开始日期。

返回属性包 (JSON 对象)

通过在 RETURN 子句中组合多个属性创建自定义 JSON 对象。

MATCH (person:Person)
RETURN {age: person.properties.age, name: person.name} AS myPropertyBag
LIMIT 1

输出

此查询将创建自定义 JSON 对象(属性包),其中包含匹配的 Person 节点中的选定属性。 属性包将人员的年龄和姓名合并为单个结构化对象。

myPropertyBag
{ “age”: 28, “name”: “Carol” }

返回整个节点和边缘

MATCH (person:Person)-[e]->(company:Company)
WHERE person.name = 'Alice'
RETURN person, e, company

输出

此查询返回 Alice 与公司(包括所有属性)关系的完整节点和边缘对象。

e 公司
{“id”:“p1”,“lbl”:“Person”,“name”:“Alice”,“properties”:{“age”: 25}} {“source”:“p1”,“target”:“c1”,“lbl”:“works_at”,“since”:2020} {“id”:“c1”,“lbl”:“Company”,“name”:“TechCorp”,“properties”:{}}

计数匹配模式

使用 COUNT\ 对模式匹配项数进行计数。

MATCH (person:Person)-[:likes]->(p2:Person)
RETURN person.name, COUNT(*) AS LikesGiven

此查询按人员姓名统计每个人喜欢和对结果进行分组的人数。

使用 MIN 和 MAX 进行聚合

查找所有匹配项的最小值和最大值。

MATCH (person:Person)
RETURN MIN(cast(person.properties.age as int)) AS Youngest, MAX(cast(person.properties.age as int)) AS Oldest

此查询查找图形中所有人员中最年轻和年龄最大的年龄。

将值收集到数组中

使用COLLECT_LIST将多个值收集到数组中。

MATCH (person:Person)
RETURN COLLECT_LIST(person.name) AS AllNames

此查询将所有人员姓名收集到单个数组中。

返回非重复值

从结果中删除重复项。

MATCH (person:Person)-[]->(company:Company)
RETURN DISTINCT company.name

此查询仅返回一次唯一的公司名称,即使多个人连接到同一家公司也是如此。

返回有序结果

使用 ORDER BY 对结果进行排序。

MATCH (person:Person)
RETURN person.name, person.properties.age
ORDER BY cast(person.properties.age as int) DESC

此查询以降序返回按年龄排序的人,先按年龄排序。

限制结果计数

限制返回的结果数。

MATCH (person:Person)
WHERE person.properties.age > 25
RETURN person.name
ORDER BY cast(person.properties.age as int)
LIMIT 5

此查询仅返回 25 岁以上的前 5 个人,按年龄排序。

可比 KQL: 类似于 KQL projectsummarizesorttake 运算符。

高级模式示例

使用高级模式可以匹配复杂的图形结构和标签组合。

标签联合 (OR)

匹配具有任何指定标签的节点:

MATCH (entity:Person | Company)
RETURN entity

此查询匹配具有“人员”或“公司”标签的节点。 管道符号 | 表示标签的逻辑 OR。

标签交集 (AND)

匹配具有所有指定标签的节点:

MATCH (person:Person & Male)
RETURN person.name

此查询匹配同时具有“Person”和“Male”标签的节点。 与数 & 表示标签的逻辑 AND。

标签否定 (NOT)

匹配没有指定标签的节点:

MATCH (person:!Female)
RETURN person.name

此查询与没有“女性”标签的所有节点匹配。 感叹号 ! 表示标签的逻辑 NOT。

具有精确范围的可变长度路径

匹配具有特定跃点数的路径:

MATCH (s)-[es]->{2,2}(e)
RETURN s, es, e

此查询查找长度正好为两个跃点的路径。 {2,2}限定符将最小路径长度和最大路径长度设置为 2。

具有开放范围的可变长度路径

匹配具有最小跃点数但没有最大值的路径:

MATCH (s)-[p]->{1,}(e)
RETURN s, e, p

此查询查找长度为一个或多个跃点的路径。 {1,}限定符表示一个或多个没有上限的跃点。

零长度路径

将节点与自身匹配(标识关系):

MATCH (n)-[]->{0,0}(same_n)
RETURN n

此查询通过零长度路径匹配每个节点本身。 {0,0}限定符将路径长度设置为零,因此每个节点与自身配对。

命名路径变量

将整个路径分配给变量供以后使用:

MATCH p = (person:Person)-[:works_at]->(company:Company)
RETURN p

此查询将整个模式分配给变量 p,可以在查询的其他部分返回或使用该模式。 路径变量具有节点和边缘的完整序列。

可选匹配

用于 OPTIONAL MATCH 查找可能不存在的模式,当模式不匹配时返回空值:

MATCH (p:Person)
    WHERE p.properties.age < 30
OPTIONAL MATCH (p)->(c:City)
    WHERE c.name <> 'Seattle' 
RETURN p.name as Person, c.name as City

此查询查找年龄小于 30 的所有 Person 节点,并可以选择匹配它们连接到的城市(不包括西雅图)。 如果某个人未连接到任何城市(或仅连接到西雅图),则 City 列将返回空,但结果中仍包含该人员。

输出

可选匹配可确保仍返回没有城市连接的人员:

人员 City
颂歌 波特兰
艾玛 波特兰
爱丽丝

多跃点命名路径

创建跨多个关系的命名路径:

MATCH full_path = (s)-[first_edge]->(middle)-[second_edge]->(e)
RETURN full_path, s.name, e.name

此查询创建一个命名路径变量,该变量 full_path 捕获双跃点模式,并从 s 和 e 节点返回特定属性。

可比 KQL: 使用高级 graph-match 运算符功能进行复杂的模式匹配。

复杂的多模式示例

使用 FILTER 交叉产品筛选

使用多个单独的 MATCH 模式时,GQL 会创建所有匹配组合的交叉积。 通过 FILTER 关键字,可以根据涉及来自不同模式的变量的条件筛选此跨产品。

此示例演示如何筛选人员和城市的交叉乘积:

MATCH (p:Person)
MATCH (c:City)
FILTER p.name = 'Carol' or c.name = 'Seattle'
RETURN p.name as Person, c.name as City
LIMIT 2

输出

人员 City
颂歌 波特兰
大卫 Seattle

此查询演示关键字 FILTER 如何在所有 Person 节点和所有 City 节点的交叉乘积上运行,仅返回人员名称为“Carol”或城市名称为“Seattle”的组合。

具有公司筛选器 跨城镇赞

此示例在一个语句中合并了多个模式和筛选器:

  1. 找到一对 p1 喜欢 p2 的人。
  2. 将每个人链接到他们的家乡。 p1 的城市名称必须 以“San”开头,p2 必须位于 不同的城市
  3. 请确保 p2 在 TechCorp 中正常工作
  4. 仅包括两人 年龄不同的对。

第一个 RETURN 显示每个资格赛(人员、他们的城市和公司),以便可以查看原始结果。 第二 RETURN 个聚合所有匹配项以输出单个值:满足这些条件 的所有“喜欢”人员 (p2)的平均年龄。

MATCH  (p1:Person)-[:likes]->(p2:Person),
       (p1)-[:located_at]->(home:City),
       (p2)-[:located_at]->(home2:City),
       (p2)-[:works_at]->(work:Company {name: 'TechCorp'})
WHERE  cast(p1.properties.age as int) <> cast(p2.properties.age as int) and home.name <> home2.name and home.name starts with 'San'
RETURN p1.name, p2.name, home.name, work.name, home2.name

输出

p1.name p2.name home.name work.name home2.name
大卫 爱丽丝 旧金山 TechCorp Seattle
MATCH  (p1:Person)-[:likes]->(p2:Person),
       (p1)-[:located_at]->(home:City),
       (p2)-[:located_at]->(home2:City),
       (p2)-[:works_at]->(work:Company {name: 'TechCorp'})
WHERE  cast(p1.properties.age as int) <> cast(p2.properties.age as int) and home.name <> home2.name and home.name starts with 'San'
RETURN AVG(cast(p2.properties.age as int)) AS AvgAgeLikedAcrossTowns

输出

AvgAgeLikedAcrossTowns
二十五

此示例演示了 GQL 如何通过跨变量筛选、内联属性匹配、字符串模式匹配和聚合来表达复杂的多模式查询,所有这些查询都在一个可读语句中。

使用 DURATION 函数进行时态数据分析

GQL 提供对使用持续时间函数进行临时数据分析的全面支持。 通过这些函数,可以使用时间戳对图形数据执行基于时间的筛选、计算和比较。

支持的持续时间单位

DURATION() 函数支持使用灵活、不区分大小写的语法并返回一个 timespan 对象的各种时间单位:

时间单位 支持的名称 Example Timespan 输出
daysday DURATION({days: 7}) 7.00:00:00
Hours hourshourHOURS DURATION({hours: 24}) 1.00:00:00
纪要 minutesminuteMINUTES DURATION({minutes: 30}) 00:30:00
secondssecondSECONDSsecOnd DURATION({seconds: 45}) 00:00:45
毫秒 millisecondsmillisecond DURATION({milliseconds: 500}) 00:00:00.5000000
微秒 microsecondsmicrosecondmicRosecond DURATION({microseconds: 1000}) 00:00:00.0010000
纳 秒 nanosecondsnanosecondnanoSecond DURATION({nanoseconds: 1000000}) 00:00:00.0010000

可以在单个持续时间对象中组合多个单位: DURATION({days: 1.8, minutes: 8, seconds: 7}) 返回 1.00:08:07

复杂的时态边界分析

将持续时间函数与时间戳算术相结合,以便进行精确的时态筛选:

MATCH (system:System)-[event:generated]->(alert:Alert)
WHERE event.event_timestamp <= zoned_datetime("2012-01-01 08:00:00.0") + DURATION({days: 3})
    AND event.event_timestamp > zoned_datetime("2012-01-01 08:00:00.0") + DURATION({minutes: 1})
RETURN 
    system.name,
    alert.severity,
    event.event_timestamp,
    DURATION_BETWEEN(zoned_datetime("2012-01-01 08:00:00.0"), event.event_timestamp) AS time_since_baseline
ORDER BY event.event_timestamp

此查询查找在特定时间范围内生成的警报(基线日期后的 1 分钟到 3 天),并计算基线与每个事件之间的持续时间。

输出

system.name alert.severity event_timestamp time_since_baseline
WebServer01 警告 2012-01-01T08:01:30.0Z 00:01:30
Database02 危急 2012-01-02T20:15:45.0Z 1.12:15:45
负载均衡器 信息 2012-01-04T16:30:00.0Z 3.08:30:00

社交网络用例:好友建议

社交媒体平台使用 GQL 根据相互关系建议潜在的朋友。
我们将使用 LDBC 社交网络基准数据集(请参阅 GQL 示例数据)。

  1. 设置图形引用以指向 LDBC 数据集。

    #crp query_graph_reference=graph('LDBC_SNB_Interactive')
    
  2. 通过相互联系查找潜在的朋友。

    MATCH (p1:PERSON {firstName: 'Karl', lastName: 'Muller'})-[:KNOWS]-(p2:PERSON)-[:KNOWS]-(p3:PERSON),
          (p1)-[:IS_LOCATED_IN]-(c1:PLACE),
          (p3)-[:IS_LOCATED_IN]-(c1)
    WHERE p1.id <> p3.id
    RETURN DISTINCT p3.firstName, p3.lastName
    

输出

此查询建议有相互联系并位于同一位置的卡尔的朋友。

p3.firstName p3.lastName
阿尔佛雷德 霍夫曼
汉斯 贝克尔
威廉 穆勒