Gremlin 查询语言

Gremlin 是 JanusGraph 的 查询语言,用于从图中检索数据和修改图中的数据。 Gremlin 是一种面向路径的语言,能够简洁地表达复杂的 图遍历和变异操作。Gremlin 是一种函数式 语言,通过 将遍历操作符链接在一起来形成类似路径的表达式。 例如,“从 Hercules 出发,遍历到他的父亲,然后是他 父亲的父亲,并返回祖父的名字。”
Gremlin是Apache TinkerPop的一个组件。它独立于JanusGraph开发,并受到大多数图数据库的支持。通过Gremlin查询语言在JanusGraph之上构建应用程序,用户可以避免供应商锁定,因为他们的应用程序可以迁移到其他支持Gremlin的图数据库。
本节简要概述Gremlin查询语言。如需更多关于Gremlin的信息,请参考以下资源:
-
Practical Gremlin: Kelvin R. Lawrence 编写的一本在线书籍,深入概述了 Gremlin 及其与 JanusGraph 的交互。
-
Complete Gremlin Manual: Gremlin所有步骤的参考手册。
-
Gremlin Console Tutorial: 学习如何有效使用Gremlin控制台以交互方式遍历和分析图。
-
Gremlin Recipes: Gremlin最佳实践和常见遍历模式的集合。
-
Gremlin Language Drivers: 使用不同编程语言连接到Gremlin服务器, 包括Go、JavaScript、.NET/C#、PHP、Python、Ruby、Scala和 TypeScript。
-
Gremlin语言变体: 学习如何在宿主编程语言中嵌入Gremlin。
-
Gremlin for SQL developers: 使用SQL查询数据时常见的典型模式来学习Gremlin。
除了这些资源,Connecting to JanusGraph 解释了如何在不同编程语言中使用Gremlin查询JanusGraph服务器。
Introductory Traversals
Gremlin查询是从左到右评估的一系列操作/函数链。下面提供了一个简单的祖父查询,基于入门指南中讨论的神图数据集。
gremlin> g.V().has('name', 'hercules').out('father').out('father').values('name')
==>saturn
上述查询可以理解为:
g: 用于当前图遍历。V: 表示图中的所有顶点has('name', 'hercules'): 将顶点过滤为具有名称属性"hercules"的顶点(只有一个)。out('father'): 从Hercules遍历出向的father边。- ‘out('father')`: 从赫拉克勒斯的父亲顶点(即木星)遍历出向的父边。
name: 获取"hercules"顶点祖父的name属性。
综合来看,这些步骤形成了一个类似路径的遍历查询。每个步骤 都可以被分解并展示其结果。这种构建遍历/查询的方式 在构建更大、更复杂的查询链时非常有用。
gremlin> g
==>graphtraversalsource[janusgraph[cql:127.0.0.1], standard]
gremlin> g.V().has('name', 'hercules')
==>v[24]
gremlin> g.V().has('name', 'hercules').out('father')
==>v[16]
gremlin> g.V().has('name', 'hercules').out('father').out('father')
==>v[20]
gremlin> g.V().has('name', 'hercules').out('father').out('father').values('name')
==>saturn
作为完整性检查,通常最好查看每个返回的属性,而不是分配的长ID。
gremlin> g.V().has('name', 'hercules').values('name')
==>hercules
gremlin> g.V().has('name', 'hercules').out('father').values('name')
==>jupiter
gremlin> g.V().has('name', 'hercules').out('father').out('father').values('name')
==>saturn
注意相关的遍历显示了赫拉克勒斯的整个父系家族树分支。提供这个更复杂的遍历是为了展示该语言的灵活性和表达能力。熟练掌握Gremlin使JanusGraph用户能够流畅地导航底层图结构。
gremlin> g.V().has('name', 'hercules').repeat(out('father')).emit().values('name')
==>jupiter
==>saturn
下面提供了更多遍历示例。
gremlin> hercules = g.V().has('name', 'hercules').next()
==>v[1536]
gremlin> g.V(hercules).out('father', 'mother').label()
==>god
==>human
gremlin> g.V(hercules).out('battled').label()
==>monster
==>monster
==>monster
gremlin> g.V(hercules).out('battled').valueMap()
==>{name=nemean}
==>{name=hydra}
==>{name=cerberus}
鉴于诸神之图仅有一位战斗者(Hercules), 为了示例,通过Gremlin向图中添加了另一位战斗者, 展示如何向图中添加顶点和边。
gremlin> theseus = graph.addVertex('human')
==>v[3328]
gremlin> theseus.property('name', 'theseus')
==>null
gremlin> cerberus = g.V().has('name', 'cerberus').next()
==>v[2816]
gremlin> battle = theseus.addEdge('battled', cerberus, 'time', 22)
==>e[7eo-2kg-iz9-268][3328-battled->2816]
gremlin> battle.values('time')
==>22
当添加顶点时,可以提供一个可选的顶点标签。添加边时必须指定边标签。属性作为键值对可以在顶点和边上设置。当属性键定义为SET或LIST基数时,向顶点添加相应属性必须使用addProperty。
gremlin> g.V(hercules).as('h').out('battled').in('battled').where(neq('h')).values('name')
==>theseus
上面的例子有4个链式函数:out、in、except和
values(即name是values('name')的简写)。每个函数的
签名如下所列,其中V是顶点,U是任意对象,且V是U的子集。
out: V -> Vin: V -> Vexcept: U -> Uvalues: V -> U
当串联函数时,传入类型必须与传出类型匹配,其中U可以匹配任何类型。因此,上述"共同战斗/盟友"遍历是正确的。
注意
本节介绍的Gremlin概览主要聚焦于Gremlin控制台中使用的Gremlin-Groovy语言实现。关于使用除Groovy之外的其他语言连接JanusGraph且独立于Gremlin控制台的信息,请参阅Connecting to JanusGraph。
Iterating the Traversal
Gremlin控制台的一个便利特性是它会自动迭代从gremlin>提示符执行查询的所有结果。这在REPL环境中运行良好,因为它以字符串形式显示结果。当你转向编写Gremlin应用程序时,理解如何显式迭代遍历非常重要,因为你的应用程序的遍历不会自动迭代。以下是迭代Traversal的一些常见方法:
iterate()- 预期结果为零或可忽略。next()- 获取一个结果。请确保先检查hasNext()。next(int n)- 获取接下来的n个结果。请确保先检查hasNext()。toList()- 将所有结果作为列表获取。如果没有结果,则返回空列表。
以下是一个Java代码示例,用于演示这些概念:
Traversal t = g.V().has("name", "pluto"); // 定义一个遍历
// 注意遍历尚未执行/迭代
Vertex pluto = null;
if (t.hasNext()) { // 检查是否有可用结果
pluto = g.V().has("name", "pluto").next(); // 获取一个结果
g.V(pluto).drop().iterate(); // 执行遍历以从图中删除pluto
}
// 注意遍历可以被克隆以供重用
Traversal tt = t.asAdmin().clone();
if (tt.hasNext()) {
System.err.println("pluto was not dropped!");
}
List<Vertex> gods = g.V().hasLabel("god").toList(); // 查找所有神