Gremlin 查询语言

Gremlin 是 JanusGraph 的查询语言,用于从图中检索数据和修改数据。Gremlin 是一种面向路径的语言,可以简洁地表达复杂的图遍历和修改操作。Gremlin 是一种函数式语言,其中遍历运算符被链式连接起来形成路径式表达式。例如,“从赫拉克勒斯出发,遍历到他的父亲,然后是他的父亲的父亲,并返回祖父的名字。”
Gremlin 是 Apache TinkerPop 的一个组件。它独立于 JanusGraph 开发,并受大多数图数据库支持。通过使用 Gremlin 查询语言在 JanusGraph 之上构建应用程序,用户可以避免供应商锁定,因为他们的应用程序可以迁移到其他支持 Gremlin 的图数据库。
本节简要概述 Gremlin 查询语言。有关 Gremlin 的更多信息,请参阅以下资源
-
Practical Gremlin:Kelvin R. Lawrence 撰写的在线书籍,深入概述了 Gremlin 及其与 JanusGraph 的交互。
-
Complete Gremlin Manual:Gremlin 所有步骤的参考手册。
-
Gremlin Console Tutorial:学习如何有效地使用 Gremlin Console 交互式地遍历和分析图。
-
Gremlin Recipes:Gremlin 的最佳实践和常见遍历模式集合。
-
Gremlin Language Drivers:使用不同的编程语言(包括 Go、JavaScript、.NET/C#、PHP、Python、Ruby、Scala 和 TypeScript)连接到 Gremlin 服务器。
-
Gremlin Language Variants:学习如何在宿主编程语言中嵌入 Gremlin。
-
Gremlin for SQL developers:使用在 SQL 查询数据时发现的典型模式学习 Gremlin。
除了这些资源,连接到 JanusGraph 解释了 Gremlin 如何在不同的编程语言中用于查询 JanusGraph 服务器。
入门遍历
Gremlin 查询是一系列从左到右评估的操作/函数链。下面提供了一个简单的祖父查询,用于入门中讨论的 Graph of the Gods 数据集。
gremlin> g.V().has('name', 'hercules').out('father').out('father').values('name')
==>saturn
以上查询可以解读为
g:表示当前图遍历。V:表示图中的所有顶点。has('name', 'hercules'):将顶点过滤为名称属性为“hercules”的顶点(只有一个)。out('father'):从赫拉克勒斯遍历出去的父边。- ‘out('father')`:从赫拉克勒斯父亲的顶点(即朱庇特)遍历出去的父边。
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}
鉴于 The Graph of the Gods 中只有一个战斗者(赫拉克勒斯),为了示例,使用 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 Console 中使用的 Gremlin-Groovy 语言实现。有关如何使用 Groovy 以外的其他语言连接到 JanusGraph 以及独立于 Gremlin Console 的信息,请参阅连接到 JanusGraph。
遍历的迭代
Gremlin Console 的一个方便功能是,它会自动迭代从 gremlin> 提示符执行的查询的所有结果。这在 REPL 环境中运行良好,因为它将结果显示为字符串。当你转向编写 Gremlin 应用程序时,了解如何显式迭代遍历非常重要,因为你的应用程序的遍历不会自动迭代。以下是一些迭代 Traversal 的常见方法
iterate()- 预期没有结果或可以忽略。next()- 获取一个结果。请务必先检查hasNext()。next(int n)- 获取接下来的n个结果。请务必先检查hasNext()。toList()- 将所有结果作为列表获取。如果没有结果,则返回空列表。
下面显示了一个 Java 代码示例来演示这些概念
Traversal t = g.V().has("name", "pluto"); // Define a traversal
// Note the traversal is not executed/iterated yet
Vertex pluto = null;
if (t.hasNext()) { // Check if results are available
pluto = g.V().has("name", "pluto").next(); // Get one result
g.V(pluto).drop().iterate(); // Execute a traversal to drop pluto from graph
}
// Note the traversal can be cloned for reuse
Traversal tt = t.asAdmin().clone();
if (tt.hasNext()) {
System.err.println("pluto was not dropped!");
}
List<Vertex> gods = g.V().hasLabel("god").toList(); // Find all the gods