Gremlin是 JanusGraph 的查询语言,用于从图中检索数据和修改数据。Gremlin 是一种面向路径的语言,它简洁地表达了复杂的图遍历和变异操作。Gremlin 是一种函数式语言,其中遍历运算符链接在一起以形成类似路径的表达式。例如,“从 Hercules,遍历到他的父亲,然后是他父亲的父亲,然后返回祖父的名字。”
Gremlin 是Apache TinkerPop 的一个组件。它是独立于 JanusGraph 开发的,被大多数图数据库支持。通过使用 Gremlin 查询语言在 JanusGraph 之上构建应用程序,用户可以避免供应商锁定,因为他们的应用程序可以迁移到其他支持 Gremlin 的图形数据库。
本节是 Gremlin 查询语言的简要概述。有关 Gremlin 的更多信息,请参阅以下资源:
Practical Gremlin:Kelvin R. Lawrence 的在线书籍,深入概述了 Gremlin 及其与 JanusGraph 的交互。
完整的 Gremlin 手册:所有 Gremlin 步骤的参考手册。
Gremlin 控制台教程:了解如何有效地使用 Gremlin 控制台以交互方式遍历和分析图形。
Gremlin Recipes:Gremlin最佳实践和常见遍历模式的集合。
Gremlin 语言驱动程序:连接到具有不同编程语言的 Gremlin 服务器,包括 Go、JavaScript、.NET/C#、PHP、Python、Ruby、Scala 和 TypeScript。
Gremlin 语言变体:了解如何将 Gremlin 嵌入到宿主编程语言中。
面向 SQL 开发人员的Gremlin:使用使用 SQL 查询数据时发现的典型模式来学习 Gremlin。
除了这些资源之外,连接到 JanusGraph 还解释了如何在不同的编程语言中使用 Gremlin 来查询 JanusGraph 服务器。
Gremlin 查询是从左到右计算的一系列操作/函数。下面提供了对入门中讨论的 Gods数据集图形的简单祖父查询。
gremlin> g.V().has('name', 'hercules').out('father').out('father').values('name')
==>saturn
上面的查询可以阅读:
g
: 用于当前图遍历。V
: 对于图中的所有顶点has('name', 'hercules')
:将顶点过滤为具有名称属性“hercules”的顶点(只有一个)。out('father')
: 从 Hercules 遍历传出的父亲边缘。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
请注意显示 Hercules 的整个父系树分支的相关遍历。提供这种更复杂的遍历是为了展示语言的灵活性和表达能力。熟练掌握 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}
每个步骤(由分隔符 . 表示)都是一个函数,用于对上一步发出的对象进行操作。Gremlin 语言中有许多步骤(请参阅Gremlin 步骤)。通过简单地改变一个步骤或步骤的顺序,不同的遍历语义被制定。下面的例子返回了所有与 Hercules 相同的怪物战斗过的人的名字,这些怪物本身不是 Hercules(即“co-battlers”或“盟友”)。
鉴于The Graph of the Gods只有一个战士 (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 -> V
in: V -> V
except: U -> U
values: V -> U
将函数链接在一起时,传入类型必须匹配传出类型,其中U
匹配任何内容。因此,上面的“co-batted/ally”遍历是正确的。
笔记
本节中介绍的 Gremlin 概述侧重于 Gremlin 控制台中使用的 Gremlin-Groovy 语言实现。有关使用 Groovy 以外的其他语言和独立于 Gremlin 控制台连接到 JanusGraph的信息,请参阅连接到 JanusGraph。
Gremlin 控制台的一项便利功能是它会自动迭代从 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